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.
Files changed (88) hide show
  1. package/CHANGELOG.md +320 -9
  2. package/README.md +104 -127
  3. package/bin/valise +67 -3266
  4. package/docs/architecture.md +76 -51
  5. package/docs/contrib-modules.md +180 -173
  6. package/docs/installation.md +210 -69
  7. package/docs/module-abi.md +211 -148
  8. package/docs/projects.md +249 -0
  9. package/docs/release-policy.md +90 -11
  10. package/docs/shared-modules.md +149 -26
  11. package/examples/README.md +20 -8
  12. package/examples/e2e/README.md +61 -68
  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 +151 -0
  31. package/examples/profile-project/bundles.tsv +8 -0
  32. package/examples/profile-project/layers/demo/module.d/contrib_demo_greeting.meta +9 -0
  33. package/examples/profile-project/layers/demo/modules/shared/contrib_demo_greeting.sh +4 -0
  34. package/examples/profile-project/module.d/greeting.meta +9 -0
  35. package/examples/profile-project/module.d/profile_main.meta +8 -0
  36. package/examples/profile-project/modules/greeting.sh +5 -0
  37. package/examples/profile-project/valise.conf +4 -0
  38. package/examples/profile-project/variants.tsv +3 -0
  39. package/examples/shared/README.md +13 -34
  40. package/examples/shared/module.d/contrib_shared_paths.meta +2 -3
  41. package/examples/shared/module.d/contrib_shared_umask.meta +1 -2
  42. package/examples/shared/modules/shared/contrib_shared_paths.sh +2 -2
  43. package/lib/capabilities.sh +40 -13
  44. package/lib/cli/commands.sh +278 -0
  45. package/lib/cli/common.sh +326 -0
  46. package/lib/cli/devtools.sh +539 -0
  47. package/lib/cli/fish-hook.sh +986 -0
  48. package/lib/cli/integration.sh +337 -0
  49. package/lib/cli/lifecycle.sh +578 -0
  50. package/lib/cli/project.sh +1807 -0
  51. package/lib/cli/store.sh +1023 -0
  52. package/lib/cli/usage.sh +308 -0
  53. package/lib/compiler.awk +352 -24
  54. package/lib/fish/loader.fish +163 -28
  55. package/lib/fish/metadata.fish +62 -19
  56. package/lib/fish/profile.fish +170 -0
  57. package/lib/loader.sh +736 -158
  58. package/lib/metadata.sh +137 -55
  59. package/manifests/parser-support.tsv +2 -2
  60. package/module.d/valise_editor.meta +9 -0
  61. package/module.d/valise_history.meta +9 -0
  62. package/module.d/valise_pager.meta +9 -0
  63. package/module.d/valise_path.meta +9 -0
  64. package/module.d/{platform_bsd.meta → valise_platform_bsd.meta} +3 -4
  65. package/module.d/{platform_linux.meta → valise_platform_linux.meta} +3 -4
  66. package/module.d/{platform_macos.meta → valise_platform_macos.meta} +3 -4
  67. package/module.d/{platform_posix.meta → valise_platform_posix.meta} +2 -3
  68. package/module.d/valise_xdg.meta +9 -0
  69. package/modules/system/{contrib_editor.sh → valise_editor.sh} +2 -2
  70. package/modules/system/{contrib_history.sh → valise_history.sh} +2 -2
  71. package/modules/system/{contrib_pager.sh → valise_pager.sh} +2 -2
  72. package/modules/system/{contrib_path.sh → valise_path.sh} +3 -3
  73. package/modules/system/{contrib_xdg.sh → valise_xdg.sh} +2 -2
  74. package/package.json +91 -9
  75. package/docs/variants.md +0 -63
  76. package/entrypoints/.gitkeep +0 -0
  77. package/entrypoints/fish/profile.fish +0 -99
  78. package/examples/e2e/build-manifest.sh +0 -250
  79. package/examples/local/.gitkeep +0 -0
  80. package/lib/.gitkeep +0 -0
  81. package/manifests/.gitkeep +0 -0
  82. package/module.d/.gitkeep +0 -0
  83. package/module.d/contrib_editor.meta +0 -10
  84. package/module.d/contrib_history.meta +0 -10
  85. package/module.d/contrib_pager.meta +0 -10
  86. package/module.d/contrib_path.meta +0 -10
  87. package/module.d/contrib_xdg.meta +0 -10
  88. package/modules/.gitkeep +0 -0
package/bin/valise CHANGED
@@ -7,3280 +7,71 @@
7
7
 
8
8
  set -eu
9
9
 
10
- VALISE_VERSION="0.1.0"
11
-
12
- # XDG defaults per install-contracts.md
13
- VALISE_XDG_DATA="${XDG_DATA_HOME:-$HOME/.local/share}/valise"
14
- VALISE_XDG_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/valise"
15
- VALISE_XDG_STATE="${XDG_STATE_HOME:-$HOME/.local/state}/valise"
16
- VALISE_RELEASES_DIR="$VALISE_XDG_DATA/releases"
17
- VALISE_ACTIVE_LINK="$VALISE_XDG_CONFIG/active"
18
- VALISE_LOCK_DIR="$VALISE_XDG_STATE/lock"
19
-
20
- usage() {
21
- printf '%s\n' \
22
- "Usage: valise <command> [options]" \
23
- "" \
24
- "Commands:" \
25
- " init [bash|zsh|ksh|fish] Output shell integration snippet" \
26
- " install Install or update the active release" \
27
- " verify-active [--print-root] Verify the sealed active release" \
28
- " doctor Run environment diagnostics" \
29
- " variant [list|use <sha>] List installed releases / switch active release" \
30
- " make-manifest <tree> [--output <file>] Write a release manifest for a tree" \
31
- " compile [--bundle=<name>] [--variant=<name>] <output-dir> (consuming project)" \
32
- " explain-variant [name] Show variant details and per-shell impact (consuming project)" \
33
- " explain-bundles Explain installed bundle roots and closure (consuming project)" \
34
- " layer-lint <name> Validate a contribution layer structure (consuming project)" \
35
- " version Print version" \
36
- "" \
37
- "Environment:" \
38
- " XDG_DATA_HOME Release storage root (default: ~/.local/share)" \
39
- " XDG_CONFIG_HOME Active pointer symlink (default: ~/.config)" \
40
- " XDG_STATE_HOME Lock and journal state (default: ~/.local/state)"
41
- }
42
-
43
- die() {
44
- printf 'valise: error: %s\n' "$*" >&2
45
- exit 1
46
- }
47
-
48
- info() {
49
- printf 'valise: %s\n' "$*"
50
- }
51
-
52
- # POSIX shell path parent extraction avoids ambient dirname resolution in
53
- # manifest discovery and every subsequent source/destination validation path.
54
- path_parent() {
55
- _path_parent_value=$1
56
- # Strip trailing slashes so "out/" and "out" share one parent (".").
57
- # Without this, path_parent("out/") is "out" itself: parent-mkdir creates
58
- # the destination, the emptiness check treats it as pre-created-empty, and
59
- # staging lands inside the destination (publish then fails ENOTEMPTY).
60
- while [ "$_path_parent_value" != "/" ] &&
61
- [ "${_path_parent_value%/}" != "$_path_parent_value" ]; do
62
- _path_parent_value=${_path_parent_value%/}
63
- done
64
- case "$_path_parent_value" in
65
- */*)
66
- _path_parent_value=${_path_parent_value%/*}
67
- [ -n "$_path_parent_value" ] || _path_parent_value=/
68
- ;;
69
- *) _path_parent_value=. ;;
70
- esac
71
- printf '%s\n' "$_path_parent_value"
72
- }
73
-
74
- # Emit a single-quoted literal for generated POSIX shell code. The generated
75
- # snippets must not interpolate user-controlled XDG paths into double quotes:
76
- # `$()` and backticks would still execute there. POSIX single quotes preserve
77
- # every character except apostrophe, which is represented by the standard
78
- # '\'' sequence.
79
- shell_quote() {
80
- _shell_quote_value=$1
81
- printf "'"
82
- while [ -n "$_shell_quote_value" ]; do
83
- _shell_quote_char=${_shell_quote_value%"${_shell_quote_value#?}"}
84
- _shell_quote_value=${_shell_quote_value#?}
85
- case "$_shell_quote_char" in
86
- "'") printf "%s" "'\\''" ;;
87
- *) printf '%s' "$_shell_quote_char" ;;
88
- esac
89
- done
90
- printf "'"
91
- }
92
-
93
- # Fish single-quoted literals use a backslash-escaped apostrophe. Encode each
94
- # source backslash as two backslashes so a backslash immediately before an
95
- # apostrophe cannot change the quote grammar. Dollar signs, semicolons, and
96
- # command-substitution markers remain literal, so arbitrary XDG paths cannot
97
- # inject Fish commands.
98
- fish_quote() {
99
- _fish_quote_value=$1
100
- printf "'"
101
- while [ -n "$_fish_quote_value" ]; do
102
- _fish_quote_char=${_fish_quote_value%"${_fish_quote_value#?}"}
103
- _fish_quote_value=${_fish_quote_value#?}
104
- case "$_fish_quote_char" in
105
- \\) printf '%s' '\\' ;;
106
- "'") printf '%s' "\\'" ;;
107
- *) printf '%s' "$_fish_quote_char" ;;
108
- esac
109
- done
110
- printf "'"
111
- }
112
-
113
- trusted_uname() {
114
- if [ -x /usr/bin/uname ]; then
115
- /usr/bin/uname "$@"
116
- elif [ -x /bin/uname ]; then
117
- /bin/uname "$@"
118
- else
119
- return 1
120
- fi
121
- }
122
-
123
- # Resolve only platform-owned utility paths for integrity operations. These
124
- # checks must not be redirected by a caller-controlled PATH.
125
- trusted_utility_path() {
126
- case "$1" in
127
- awk) _trusted_candidates='/usr/bin/awk /bin/awk' ;;
128
- cat) _trusted_candidates='/bin/cat /usr/bin/cat' ;;
129
- cp) _trusted_candidates='/bin/cp /usr/bin/cp' ;;
130
- chmod) _trusted_candidates='/bin/chmod /usr/bin/chmod' ;;
131
- cmp) _trusted_candidates='/usr/bin/cmp /bin/cmp' ;;
132
- ln) _trusted_candidates='/bin/ln /usr/bin/ln' ;;
133
- mkdir) _trusted_candidates='/bin/mkdir /usr/bin/mkdir' ;;
134
- kill) _trusted_candidates='/bin/kill /usr/bin/kill' ;;
135
- mktemp) _trusted_candidates='/usr/bin/mktemp /bin/mktemp /opt/homebrew/bin/mktemp /usr/local/bin/mktemp' ;;
136
- readlink) _trusted_candidates='/usr/bin/readlink /bin/readlink' ;;
137
- rmdir) _trusted_candidates='/bin/rmdir /usr/bin/rmdir' ;;
138
- find) _trusted_candidates='/usr/bin/find /bin/find' ;;
139
- fish) _trusted_candidates='/opt/homebrew/bin/fish /usr/local/bin/fish /usr/bin/fish /bin/fish' ;;
140
- mv) _trusted_candidates='/bin/mv /usr/bin/mv' ;;
141
- rm) _trusted_candidates='/bin/rm /usr/bin/rm' ;;
142
- stat) _trusted_candidates='/usr/bin/stat /bin/stat' ;;
143
- tr) _trusted_candidates='/usr/bin/tr /bin/tr' ;;
144
- wc) _trusted_candidates='/usr/bin/wc /bin/wc' ;;
145
- sha256sum) _trusted_candidates='/usr/bin/sha256sum /bin/sha256sum /sbin/sha256sum /opt/homebrew/bin/sha256sum /usr/local/bin/sha256sum' ;;
146
- sha256) _trusted_candidates='/usr/bin/sha256 /bin/sha256 /sbin/sha256 /opt/homebrew/bin/sha256 /usr/local/bin/sha256' ;;
147
- shasum) _trusted_candidates='/usr/bin/shasum /bin/shasum /opt/homebrew/bin/shasum /usr/local/bin/shasum' ;;
148
- sort) _trusted_candidates='/usr/bin/sort /bin/sort' ;;
149
- *) return 1 ;;
150
- esac
151
- for _trusted_candidate in $_trusted_candidates; do
152
- if [ -x "$_trusted_candidate" ]; then
153
- printf '%s\n' "$_trusted_candidate"
154
- return 0
155
- fi
156
- done
157
- return 1
158
- }
159
-
160
- readlink_target() {
161
- _readlink_path=$(trusted_utility_path readlink) || return 1
162
- "$_readlink_path" "$1"
163
- }
164
-
165
- # Return a file's three-digit permission mode in the manifest's octal form.
166
- # BSD stat and GNU stat use different option spellings, so probe both.
167
- file_mode() {
168
- _stat_path=$(trusted_utility_path stat) || return 1
169
- # BSD stat accepts -f; GNU stat accepts -c. GNU stat may nevertheless
170
- # accept -f as a filesystem-stat format and exit successfully, so select a
171
- # result by validating the output rather than relying on exit status alone.
172
- _mode_value=$("$_stat_path" -f '%Lp' "$1" 2>/dev/null || :)
173
- case "$_mode_value" in
174
- [0-7][0-7][0-7]) printf '0%s\n' "$_mode_value"; return 0 ;;
175
- esac
176
- _mode_value=$("$_stat_path" -c '%a' "$1" 2>/dev/null || :) || return 1
177
- case "$_mode_value" in
178
- [0-7][0-7][0-7]) printf '0%s\n' "$_mode_value" ;;
179
- *) return 1 ;;
180
- esac
181
- }
182
-
183
- # Return a regular file's exact byte count without locale-dependent padding.
184
- file_bytes() {
185
- _wc_path=$(trusted_utility_path wc) || return 1
186
- _tr_path=$(trusted_utility_path tr) || return 1
187
- "$_wc_path" -c < "$1" | "$_tr_path" -d '[:space:]'
188
- }
189
-
190
- file_sha256() {
191
- _sha_path=$(trusted_utility_path sha256sum 2>/dev/null || :)
192
- if [ -n "$_sha_path" ]; then
193
- _sha_output=$("$_sha_path" "$1") || return 1
194
- else
195
- _sha_path=$(trusted_utility_path shasum 2>/dev/null || :)
196
- if [ -n "$_sha_path" ]; then
197
- _sha_output=$("$_sha_path" -a 256 "$1") || return 1
198
- else
199
- _sha_path=$(trusted_utility_path sha256 2>/dev/null || :)
200
- [ -n "$_sha_path" ] || return 1
201
- _sha_output=$("$_sha_path" "$1") || return 1
202
- fi
203
- fi
204
- # Supported utilities: sha256sum/shasum print "digest filename";
205
- # BSD sha256 prints "SHA256 (filename) = digest" or just the digest.
206
- # The BSD format strip must be gated behind the SHA256 ( prefix: a
207
- # blanket *=* match corrupts sha256sum/shasum output whenever the
208
- # absolute file path contains "= " (equals followed by space).
209
- case "$_sha_output" in
210
- "SHA256 ("*) _sha_output=${_sha_output##* = } ;;
211
- esac
212
- _sha_output=${_sha_output%% *}
213
- _sha_output=${_sha_output%%$(printf '\t')*}
214
- printf '%s\n' "$_sha_output"
215
- }
216
-
217
- lower_hex() {
218
- _tr_path=$(trusted_utility_path tr) || return 1
219
- "$_tr_path" 'A-F' 'a-f'
220
- }
221
-
222
- # Acquire atomic lock via mkdir (POSIX atomic operation). Every utility that
223
- # participates in lock integrity is resolved by absolute path so PATH cannot
224
- # forge ownership or suppress stale-lock cleanup.
225
- _lock_owned=0
226
- _active_tmp=""
227
- _active_backup=""
228
- _publish_tmp=""
229
- _manifest_rows=""
230
- _manifest_parse=""
231
- _stage=""
232
- _hook_tmp=""
233
- _mm_tmp=""
234
- _posix_tmp=""
235
- _mv_path=""
236
- _cleanup_failed=0
237
- acquire_lock() {
238
- _lock_cat_path=$(trusted_utility_path cat) || die "no trusted cat utility available"
239
- _lock_mkdir_path=$(trusted_utility_path mkdir) || die "no trusted mkdir utility available"
240
- _lock_rm_path=$(trusted_utility_path rm) || die "no trusted rm utility available"
241
- _lock_kill_path=$(trusted_utility_path kill) || die "no trusted kill utility available"
242
-
243
- # Reentrant ownership is valid only for a real lock directory and a real,
244
- # non-symlink pid file containing this process's exact PID.
245
- if [ "$_lock_owned" -eq 1 ] && [ -d "$VALISE_LOCK_DIR" ] && [ ! -L "$VALISE_LOCK_DIR" ] &&
246
- [ -f "$VALISE_LOCK_DIR/pid" ] && [ ! -L "$VALISE_LOCK_DIR/pid" ]; then
247
- _existing_pid=$("$_lock_cat_path" "$VALISE_LOCK_DIR/pid" 2>/dev/null || :)
248
- case "$_existing_pid" in
249
- ''|*[!0-9]*) : ;;
250
- "$$") _lock_owned=1; return 0 ;;
251
- esac
252
- fi
253
-
254
- _lock_parent=${VALISE_LOCK_DIR%/*}
255
- [ -n "$_lock_parent" ] || _lock_parent=/
256
- if [ ! -d "$_lock_parent" ]; then
257
- "$_lock_mkdir_path" -p "$_lock_parent" 2>/dev/null || die "cannot create lock parent: $_lock_parent"
258
- fi
259
- if ! "$_lock_mkdir_path" -m 700 "$VALISE_LOCK_DIR" 2>/dev/null; then
260
- # Check for stale lock using only the trusted utility paths. An invalid or
261
- # unreadable lock is fail-closed rather than treated as stale.
262
- if [ -d "$VALISE_LOCK_DIR" ] && [ ! -L "$VALISE_LOCK_DIR" ] &&
263
- [ -f "$VALISE_LOCK_DIR/pid" ] && [ ! -L "$VALISE_LOCK_DIR/pid" ]; then
264
- _lock_pid=$("$_lock_cat_path" "$VALISE_LOCK_DIR/pid" 2>/dev/null || :)
265
- case "$_lock_pid" in
266
- ''|*[!0-9]*) die "another valise process is running (unreadable lock)" ;;
267
- esac
268
- if ! "$_lock_kill_path" -0 "$_lock_pid" 2>/dev/null; then
269
- info "removing stale lock (pid $_lock_pid)"
270
- "$_lock_rm_path" -rf "$VALISE_LOCK_DIR" 2>/dev/null || die "failed to remove stale lock"
271
- if [ -e "$VALISE_LOCK_DIR" ] || [ -L "$VALISE_LOCK_DIR" ]; then
272
- die "failed to remove stale lock"
273
- fi
274
- "$_lock_mkdir_path" -m 700 "$VALISE_LOCK_DIR" 2>/dev/null || die "failed to acquire lock after stale cleanup"
275
- else
276
- die "another valise process is running (pid $_lock_pid)"
277
- fi
278
- else
279
- die "failed to acquire lock: $VALISE_LOCK_DIR"
280
- fi
281
- fi
282
- [ -d "$VALISE_LOCK_DIR" ] && [ ! -L "$VALISE_LOCK_DIR" ] || die "lock directory is not safe"
283
- printf '%s\n' "$$" > "$VALISE_LOCK_DIR/pid" || die "failed to write lock ownership"
284
- [ -f "$VALISE_LOCK_DIR/pid" ] && [ ! -L "$VALISE_LOCK_DIR/pid" ] || die "lock ownership file is not safe"
285
- _lock_pid=$("$_lock_cat_path" "$VALISE_LOCK_DIR/pid" 2>/dev/null || :)
286
- [ "$_lock_pid" = "$$" ] || die "failed to verify lock ownership"
287
- _lock_owned=1
288
- }
289
-
290
- remove_tree() {
291
- _remove_tree_path=$1
292
- _remove_chmod_path=$(trusted_utility_path chmod) || return 1
293
- _remove_rm_path=$(trusted_utility_path rm) || return 1
294
- if [ -d "$_remove_tree_path" ] && [ ! -L "$_remove_tree_path" ]; then
295
- "$_remove_chmod_path" -R u+w "$_remove_tree_path" 2>/dev/null || return 1
296
- fi
297
- "$_remove_rm_path" -rf "$_remove_tree_path" 2>/dev/null || return 1
298
- [ ! -e "$_remove_tree_path" ] && [ ! -L "$_remove_tree_path" ]
299
- }
300
-
301
- seal_tree() {
302
- _seal_tree_root=$1
303
- _find_path=$(trusted_utility_path find) || return 1
304
- _seal_chmod_path=$(trusted_utility_path chmod) || return 1
305
- "$_find_path" "$_seal_tree_root" -type d -exec "$_seal_chmod_path" 0555 {} + 2>/dev/null || return 1
306
- _seal_tree_dirs=$("$_find_path" "$_seal_tree_root" -type d -print) || return 1
307
- while IFS= read -r _seal_tree_dir; do
308
- [ -n "$_seal_tree_dir" ] || continue
309
- [ "$(file_mode "$_seal_tree_dir")" = "0555" ] || return 1
310
- done <<EOF
311
- $_seal_tree_dirs
312
- EOF
313
- return 0
314
- }
315
-
316
- release_lock() {
317
- _release_rm_path=$(trusted_utility_path rm 2>/dev/null || :)
318
- _release_rmdir_path=$(trusted_utility_path rmdir 2>/dev/null || :)
319
- if [ -n "$_active_tmp" ]; then
320
- [ -n "$_release_rm_path" ] && "$_release_rm_path" -f "$_active_tmp" 2>/dev/null || :
321
- if [ -e "$_active_tmp" ] || [ -L "$_active_tmp" ]; then _cleanup_failed=1; fi
322
- _active_tmp=""
323
- fi
324
- if [ -n "$_active_backup" ]; then
325
- if [ -L "$_active_backup" ] && [ ! -e "$VALISE_ACTIVE_LINK" ] && [ ! -L "$VALISE_ACTIVE_LINK" ]; then
326
- [ -n "$_mv_path" ] && "$_mv_path" "$_active_backup" "$VALISE_ACTIVE_LINK" 2>/dev/null || :
327
- else
328
- [ -n "$_release_rm_path" ] && "$_release_rm_path" -f "$_active_backup" 2>/dev/null || :
329
- fi
330
- if [ -e "$_active_backup" ] || [ -L "$_active_backup" ]; then _cleanup_failed=1; fi
331
- _active_backup=""
332
- fi
333
- if [ -n "$_publish_tmp" ]; then
334
- remove_tree "$_publish_tmp" || _cleanup_failed=1
335
- _publish_tmp=""
336
- fi
337
- if [ -n "$_manifest_rows" ]; then
338
- [ -n "$_release_rm_path" ] && "$_release_rm_path" -f "$_manifest_rows" 2>/dev/null || :
339
- if [ -e "$_manifest_rows" ] || [ -L "$_manifest_rows" ]; then _cleanup_failed=1; fi
340
- _manifest_rows=""
341
- fi
342
- if [ -n "$_manifest_parse" ]; then
343
- [ -n "$_release_rm_path" ] && "$_release_rm_path" -f "$_manifest_parse" 2>/dev/null || :
344
- if [ -e "$_manifest_parse" ] || [ -L "$_manifest_parse" ]; then _cleanup_failed=1; fi
345
- _manifest_parse=""
346
- fi
347
- if [ -n "$_stage" ]; then
348
- remove_tree "$_stage" || _cleanup_failed=1
349
- _stage=""
350
- fi
351
- if [ -n "$_hook_tmp" ]; then
352
- [ -n "$_release_rm_path" ] && "$_release_rm_path" -f "$_hook_tmp" 2>/dev/null || :
353
- if [ -e "$_hook_tmp" ] || [ -L "$_hook_tmp" ]; then _cleanup_failed=1; fi
354
- _hook_tmp=""
355
- fi
356
- if [ -n "$_mm_tmp" ]; then
357
- [ -n "$_release_rm_path" ] && "$_release_rm_path" -f "$_mm_tmp" 2>/dev/null || :
358
- if [ -e "$_mm_tmp" ] || [ -L "$_mm_tmp" ]; then _cleanup_failed=1; fi
359
- _mm_tmp=""
360
- fi
361
- if [ -n "$_posix_tmp" ]; then
362
- [ -n "$_release_rm_path" ] && "$_release_rm_path" -f "$_posix_tmp" 2>/dev/null || :
363
- if [ -e "$_posix_tmp" ] || [ -L "$_posix_tmp" ]; then _cleanup_failed=1; fi
364
- _posix_tmp=""
365
- fi
366
- [ "$_lock_owned" -eq 1 ] || { [ "$_cleanup_failed" -eq 0 ]; return; }
367
- [ -n "$_release_rm_path" ] && "$_release_rm_path" -f "$VALISE_LOCK_DIR/pid" 2>/dev/null || :
368
- if [ -e "$VALISE_LOCK_DIR/pid" ] || [ -L "$VALISE_LOCK_DIR/pid" ]; then _cleanup_failed=1; fi
369
- [ -n "$_release_rmdir_path" ] && "$_release_rmdir_path" "$VALISE_LOCK_DIR" 2>/dev/null || :
370
- if [ -e "$VALISE_LOCK_DIR" ] || [ -L "$VALISE_LOCK_DIR" ]; then _cleanup_failed=1; fi
371
- _lock_owned=0
372
- [ "$_cleanup_failed" -eq 0 ]
373
- }
374
-
375
- _handle_int() {
376
- trap - INT
377
- release_lock
378
- exit 130
379
- }
380
-
381
- _handle_term() {
382
- trap - TERM
383
- release_lock
384
- exit 143
385
- }
386
-
387
- trap '_exit_status=$?; release_lock; if [ "$_exit_status" -eq 0 ] && [ "$_cleanup_failed" -ne 0 ]; then _exit_status=1; fi; exit "$_exit_status"' EXIT
388
- trap '_handle_int' INT
389
- trap '_handle_term' TERM
390
-
391
- switch_active_link() {
392
- _ln_path=$(trusted_utility_path ln) || die "no trusted ln utility available"
393
- _readlink_path=$(trusted_utility_path readlink) || die "no trusted readlink utility available"
394
- if [ -e "$VALISE_ACTIVE_LINK" ] && [ ! -L "$VALISE_ACTIVE_LINK" ]; then
395
- die "active path exists and is not a symlink: $VALISE_ACTIVE_LINK"
396
- fi
397
- # ln -sfn replaces the destination symlink. On both BSD and GNU systems,
398
- # this executes unlink(2) followed by symlink(2), which is not atomic but
399
- # is the most portable approach available in pure POSIX sh (mv -h is
400
- # BSD-only, mv -T is GNU-only). The -n flag prevents following a
401
- # destination that is a symlink to a directory, making the swap act on
402
- # the symlink itself rather than descending into its target.
403
- "$_ln_path" -sfn "$1" "$VALISE_ACTIVE_LINK" || die "failed to update active symlink"
404
- [ -L "$VALISE_ACTIVE_LINK" ] || die "active symlink was not created"
405
- [ "$($_readlink_path "$VALISE_ACTIVE_LINK" 2>/dev/null)" = "$1" ] || die "active symlink target mismatch"
406
- }
407
-
408
- source_path_is_physical() {
409
- _source_root=$1
410
- _source_relative=$2
411
- _source_path=$_source_root
412
- _source_remaining=$_source_relative
413
- while [ -n "$_source_remaining" ]; do
414
- case "$_source_remaining" in
415
- */*)
416
- _source_component=${_source_remaining%%/*}
417
- _source_remaining=${_source_remaining#*/}
418
- ;;
419
- *)
420
- _source_component=$_source_remaining
421
- _source_remaining=
422
- ;;
423
- esac
424
- [ -n "$_source_component" ] || return 1
425
- _source_path=$_source_path/$_source_component
426
- [ ! -L "$_source_path" ] || return 1
427
- done
428
- return 0
429
- }
430
-
431
- validate_manifest() {
432
- _awk_path=$(trusted_utility_path awk) || return 1
433
- "$_awk_path" -F '\t' '
434
- NR == 1 { if ($0 != "shell-profile-release-manifest-v1") exit 10; next }
435
- NR == 2 { if ($1 != "destination" || $2 != "source" || $3 != "source_mode" || $4 != "install_mode" || $5 != "bytes" || $6 != "sha256" || NF != 6) exit 11; next }
436
- NF == 0 { next }
437
- NF != 6 || $1 == "" || $2 == "" || $1 !~ /^[A-Za-z0-9._\/-]+$/ || $2 !~ /^[A-Za-z0-9._\/-]+$/ || $1 ~ /^\// || $2 ~ /^\// || $1 ~ /\/$/ || $2 ~ /\/$/ || $1 ~ /^#/ || $1 == "destination" || $1 == "shell-profile-release-manifest-v1" || $3 !~ /^0(644|755)$/ || $4 != (($3 == "0644") ? "0444" : "0555") || $5 !~ /^[0-9]+$/ || length($6) != 64 || $6 !~ /^[0-9a-fA-F]+$/ || $1 ~ /(^|\/)\.($|\/)/ || index($1, "//") || $1 ~ /(^|\/)\.\.($|\/)/ || index($2, "//") || $2 ~ /(^|\/)\.($|\/)/ || $2 ~ /(^|\/)\.\.($|\/)/ || seen[$1]++ || seen_source[$2]++ { exit 12 }
438
- { data_rows = 1 }
439
- END { if (NR < 3 || data_rows != 1) exit 13 }
440
- ' "$1"
441
- }
442
-
443
- temp_path_is_safe() {
444
- _temp_candidate=$1
445
- _temp_kind=$2
446
- _temp_root=${3:-${TMPDIR:-/tmp}}
447
- case "$_temp_root" in /*) ;; *) return 1 ;; esac
448
- case "$_temp_candidate" in /*) ;; *) return 1 ;; esac
449
- [ -e "$_temp_candidate" ] || return 1
450
- [ ! -L "$_temp_candidate" ] || return 1
451
- case "$_temp_kind" in
452
- file) [ -f "$_temp_candidate" ] || return 1 ;;
453
- dir) [ -d "$_temp_candidate" ] || return 1 ;;
454
- *) return 1 ;;
455
- esac
456
- _temp_root_canonical=$(cd "$_temp_root" 2>/dev/null && pwd -P) || return 1
457
- _temp_parent=${_temp_candidate%/*}
458
- [ "$_temp_parent" != "$_temp_candidate" ] || _temp_parent=/
459
- _temp_parent_canonical=$(cd "$_temp_parent" 2>/dev/null && pwd -P) || return 1
460
- case "$_temp_parent_canonical/" in
461
- "$_temp_root_canonical/"*) ;;
462
- *) return 1 ;;
463
- esac
464
- return 0
465
- }
466
-
467
- trusted_mktemp_at() {
468
- _temp_root=$1
469
- _temp_kind=$2
470
- _temp_template=$3
471
- _mktemp_path=$(trusted_utility_path mktemp) || return 1
472
- case "$_temp_kind" in
473
- file) _temp_candidate=$("$_mktemp_path" "$_temp_template") || return 1 ;;
474
- dir) _temp_candidate=$("$_mktemp_path" -d "$_temp_template") || return 1 ;;
475
- *) return 1 ;;
476
- esac
477
- temp_path_is_safe "$_temp_candidate" "$_temp_kind" "$_temp_root" || return 1
478
- printf '%s\n' "$_temp_candidate"
479
- }
480
-
481
- trusted_mktemp() {
482
- trusted_mktemp_at "${TMPDIR:-/tmp}" "$@"
483
- }
10
+ VALISE_VERSION="0.3.0"
11
+
12
+ # The path this CLI was invoked by, made absolute before -C can change the
13
+ # working directory. The Fish hook calls the CLI back through it, so a package
14
+ # symlink stays the entry point across upgrades.
15
+ case "$0" in
16
+ /*) _valise_cli_path=$0 ;;
17
+ *) _valise_cli_path="$(pwd -P)/$0" ;;
18
+ esac
484
19
 
485
- prepare_manifest_rows() {
486
- _cleanup_rm_path=$(trusted_utility_path rm) || return 1
487
- if [ -n "$_manifest_rows" ]; then
488
- "$_cleanup_rm_path" -f "$_manifest_rows" 2>/dev/null || :
489
- _manifest_rows=""
490
- fi
491
- if [ -n "$_manifest_parse" ]; then
492
- "$_cleanup_rm_path" -f "$_manifest_parse" 2>/dev/null || :
493
- _manifest_parse=""
494
- fi
495
- # _manifest_rows is the exact private snapshot used for identity and
496
- # publication. Parsing is performed from a second file that only adds a
497
- # final newline, so an unterminated source row is still consumed by POSIX
498
- # read without changing the bytes whose digest defines the release.
499
- _manifest_rows=$(trusted_mktemp file "${TMPDIR:-/tmp}/valise-manifest.XXXXXX") || return 1
500
- _cat_path=$(trusted_utility_path cat) || {
501
- "$_cleanup_rm_path" -f "$_manifest_rows" 2>/dev/null || :
502
- _manifest_rows=""
503
- return 1
504
- }
505
- "$_cat_path" "$1" >"$_manifest_rows" || {
506
- "$_cleanup_rm_path" -f "$_manifest_rows" 2>/dev/null || :
507
- _manifest_rows=""
508
- return 1
509
- }
510
- _manifest_parse=$(trusted_mktemp file "${TMPDIR:-/tmp}/valise-manifest-parse.XXXXXX") || {
511
- "$_cleanup_rm_path" -f "$_manifest_rows" 2>/dev/null || :
512
- _manifest_rows=""
513
- return 1
514
- }
515
- _awk_path=$(trusted_utility_path awk) || {
516
- "$_cleanup_rm_path" -f "$_manifest_rows" "$_manifest_parse" 2>/dev/null || :
517
- _manifest_rows=""
518
- _manifest_parse=""
519
- return 1
20
+ # Locate the engine from this script's physical path, so package installs
21
+ # that expose bin/valise through a symlink (bun, npm) still find ../lib. This
22
+ # runs before any helper is loaded, so it uses only parameter expansion,
23
+ # readlink, cd and pwd.
24
+ _valise_self=$0
25
+ while [ -L "$_valise_self" ]; do
26
+ _valise_link=$(readlink "$_valise_self") || {
27
+ printf 'valise: error: cannot resolve %s\n' "$_valise_self" >&2
28
+ exit 1
520
29
  }
521
- "$_awk_path" '{ print }' "$_manifest_rows" >"$_manifest_parse" || {
522
- "$_cleanup_rm_path" -f "$_manifest_rows" "$_manifest_parse" 2>/dev/null || :
523
- _manifest_rows=""
524
- _manifest_parse=""
525
- return 1
526
- }
527
- }
528
-
529
- locate_manifest() {
530
- _loc_script_dir=$(cd "$(path_parent "$0")" && pwd -P) || return 1
531
- _loc_repo_root="$_loc_script_dir/.."
532
- for _loc_candidate in "$_loc_repo_root/../shell/install/profile-release.manifest" "$_loc_repo_root/shell/install/profile-release.manifest" "./shell/install/profile-release.manifest"
533
- do
534
- if [ -f "$_loc_candidate" ]; then
535
- printf '%s\n' "$_loc_candidate"
536
- return 0
537
- fi
538
- done
539
- return 1
540
- }
541
-
542
- _manifest_has_file() {
543
- _awk_path=$(trusted_utility_path awk) || return 1
544
- "$_awk_path" -F '\t' -v destination="$2" '
545
- NR > 2 && NF && $1 == destination { found = 1 }
546
- END { exit found ? 0 : 1 }
547
- ' "$1"
548
- }
549
-
550
- _manifest_has_descendant() {
551
- _awk_path=$(trusted_utility_path awk) || return 1
552
- "$_awk_path" -F '\t' -v prefix="$2/" '
553
- NR > 2 && NF && index($1, prefix) == 1 { found = 1 }
554
- END { exit found ? 0 : 1 }
555
- ' "$1"
556
- }
557
-
558
- verify_release_dir() {
559
- _verify_dir=$1
560
- _verify_manifest=$2
561
- _verify_canonical=$(cd "$_verify_dir" 2>/dev/null && pwd -P) || die "cannot resolve release root"
562
- [ "$(file_mode "$_verify_dir")" = "0555" ] || die "release root mode mismatch"
563
- _verify_snapshot="$_verify_dir/.valise-manifest"
564
- if [ -e "$_verify_snapshot" ] || [ -L "$_verify_snapshot" ]; then
565
- [ -f "$_verify_snapshot" ] || die "release manifest snapshot is not a regular file"
566
- [ ! -L "$_verify_snapshot" ] || die "release manifest snapshot must not be a symlink"
567
- [ "$(file_mode "$_verify_snapshot")" = "0444" ] || die "release manifest snapshot mode mismatch"
568
- [ "$(file_bytes "$_verify_snapshot")" = "$(file_bytes "$_verify_manifest")" ] || die "release manifest snapshot byte count mismatch"
569
- _verify_snapshot_digest=$(file_sha256 "$_verify_snapshot") || die "no SHA-256 utility available"
570
- _verify_manifest_digest=$(file_sha256 "$_verify_manifest") || die "no SHA-256 utility available"
571
- [ "$_verify_snapshot_digest" = "$_verify_manifest_digest" ] || die "release manifest snapshot digest mismatch"
572
- _verify_expected_id="${3:-}"
573
- if [ -z "$_verify_expected_id" ]; then
574
- _verify_expected_id=$(basename "$_verify_dir")
575
- fi
576
- [ "$_verify_snapshot_digest" = "$_verify_expected_id" ] || die "release manifest snapshot identity mismatch"
577
- fi
578
- while IFS="$(printf '\t')" read -r _dest _src _mode _imode _size _sha; do
579
- [ -n "$_dest" ] || continue
580
- case "$_dest" in shell-profile-release-manifest-v1|destination) continue ;; esac
581
- _verify_file="$_verify_dir/$_dest"
582
- [ -f "$_verify_file" ] || die "release file missing: $_dest"
583
- [ ! -L "$_verify_file" ] || die "release file must not be a symlink: $_dest"
584
- _verify_parent=$(cd "$(path_parent "$_verify_file")" 2>/dev/null && pwd -P) || die "release parent missing: $_dest"
585
- case "$_verify_parent/" in "$_verify_canonical/"*) : ;; *) die "release path escapes target: $_dest" ;; esac
586
- [ "$(file_mode "$_verify_file")" = "$_imode" ] || die "release mode mismatch for $_dest"
587
- [ "$(file_bytes "$_verify_file")" = "$_size" ] || die "release byte count mismatch for $_dest"
588
- case "$_sha" in *[!0123456789abcdefABCDEF]*) die "invalid release digest for $_dest" ;; esac
589
- [ "${#_sha}" -eq 64 ] || die "invalid release digest for $_dest"
590
- _verify_actual=$(file_sha256 "$_verify_file") || die "no trusted SHA-256 utility available"
591
- _verify_expected=$(printf '%s' "$_sha" | lower_hex) || die "no trusted tr utility available"
592
- [ "$_verify_actual" = "$_verify_expected" ] || die "release digest mismatch for $_dest"
593
- done < "${_manifest_parse:-$_manifest_rows}"
594
- _find_path=$(trusted_utility_path find) || die "no trusted find utility available"
595
- _verify_bad=$("$_find_path" "$_verify_dir" -print | while IFS= read -r _verify_path; do
596
- [ "$_verify_path" = "$_verify_dir" ] && continue
597
- if [ -L "$_verify_path" ]; then
598
- printf '%s\n' "$_verify_path"
599
- break
600
- fi
601
- _verify_relative=${_verify_path#"$_verify_dir"/}
602
- [ "$_verify_relative" = ".valise-manifest" ] && continue
603
- if [ -f "$_verify_path" ]; then
604
- _manifest_has_file "$_verify_manifest" "$_verify_relative" || { printf '%s\n' "$_verify_path"; break; }
605
- elif [ -d "$_verify_path" ]; then
606
- if [ "$(file_mode "$_verify_path")" != "0555" ] || ! _manifest_has_descendant "$_verify_manifest" "$_verify_relative"; then
607
- printf '%s\n' "$_verify_path"
608
- break
609
- fi
610
- else
611
- printf '%s\n' "$_verify_path"
612
- break
613
- fi
614
- done)
615
- [ -z "$_verify_bad" ] || die "release contains unmanifested or mutable path: $_verify_bad"
616
- }
617
-
618
- # --- Subcommands ---
619
-
620
- cmd_version() {
621
- printf '%s\n' "$VALISE_VERSION"
622
- }
623
-
624
- print_fish_integration() {
625
- _fish_active_literal=$(fish_quote "$VALISE_ACTIVE_LINK") || return 1
626
- _fish_cli_dir=$(cd "$(path_parent "$0")" 2>/dev/null && pwd -P) || return 1
627
- _fish_cli_path="$_fish_cli_dir/${0##*/}"
628
- _fish_cli_literal=$(fish_quote "$_fish_cli_path") || return 1
629
- _fish_source_tree_mode=${_fish_source_tree_mode:-0}
630
- printf '%s\n' \
631
- "# valise shell integration" \
632
- "begin" \
633
- "set -l _valise_fish_source_tree_mode $_fish_source_tree_mode" \
634
- "set -l _valise_fish_previous_root ''" \
635
- "if builtin set -q SHELL_PROJECT_ROOT; and builtin test (builtin count \$SHELL_PROJECT_ROOT) -eq 1" \
636
- " set _valise_fish_previous_root (builtin path resolve -- \"\$SHELL_PROJECT_ROOT\" 2>/dev/null)" \
637
- "end" \
638
- "# Authenticate the universal-variable store before any untrusted release source runs." \
639
- "set -l _valise_fish_persistence_config_home ''" \
640
- "if builtin set -q XDG_CONFIG_HOME; and test -n \"\$XDG_CONFIG_HOME\"" \
641
- " set _valise_fish_persistence_config_home \"\$XDG_CONFIG_HOME\"" \
642
- "else if builtin set -q HOME; and test -n \"\$HOME\"" \
643
- " set _valise_fish_persistence_config_home \"\$HOME/.config\"" \
644
- "else" \
645
- " builtin exit 125" \
646
- "end" \
647
- "set -l _valise_fish_persistence_durable_file \"\$_valise_fish_persistence_config_home/fish/fish_variables\"" \
648
- "set -g _valise_fish_persistence_path_physical_helper __valise_fish_path_(builtin random)" \
649
- "function \$_valise_fish_persistence_path_physical_helper --no-scope-shadowing" \
650
- " set -l _persistence_path \$argv[1]" \
651
- " if test -x /usr/bin/uname; and test (/usr/bin/uname -s 2>/dev/null) = Darwin" \
652
- " if builtin test -L /var; and test (builtin path resolve -- /var 2>/dev/null) = /private/var" \
653
- " switch \"\$_persistence_path\"" \
654
- " case /var" \
655
- " set _persistence_path /private/var" \
656
- " case '/var/*'" \
657
- " set _persistence_path (builtin string replace -r '^/var' /private/var -- \"\$_persistence_path\")" \
658
- " end" \
659
- " end" \
660
- " if builtin test -L /tmp; and test (builtin path resolve -- /tmp 2>/dev/null) = /private/tmp" \
661
- " switch \"\$_persistence_path\"" \
662
- " case /tmp" \
663
- " set _persistence_path /private/tmp" \
664
- " case '/tmp/*'" \
665
- " set _persistence_path (builtin string replace -r '^/tmp' /private/tmp -- \"\$_persistence_path\")" \
666
- " end" \
667
- " end" \
668
- " end" \
669
- " if not builtin string match -q '/*' -- \"\$_persistence_path\"; or builtin string match -q '*//*' -- \"\$_persistence_path\"" \
670
- " return 1" \
671
- " end" \
672
- " set _persistence_prefix /" \
673
- " for _persistence_component in (builtin string split '/' -- \"\$_persistence_path\")" \
674
- " if test -z \"\$_persistence_component\"" \
675
- " continue" \
676
- " end" \
677
- " switch \"\$_persistence_component\"" \
678
- " case . .." \
679
- " return 1" \
680
- " end" \
681
- " if test \"\$_persistence_prefix\" = /" \
682
- " set _persistence_prefix /\$_persistence_component" \
683
- " else" \
684
- " set _persistence_prefix \"\$_persistence_prefix/\$_persistence_component\"" \
685
- " end" \
686
- " if builtin test -L \"\$_persistence_prefix\"" \
687
- " return 1" \
688
- " end" \
689
- " end" \
690
- " return 0" \
691
- "end" \
692
- "if not \$_valise_fish_persistence_path_physical_helper \"\$_valise_fish_persistence_durable_file\"" \
693
- " builtin exit 125" \
694
- "end" \
695
- "# Capture an absolute, writable, searchable temp parent before untrusted source." \
696
- "set -l _valise_fish_persistence_tmp_parent /tmp" \
697
- "if builtin set -q TMPDIR; and test -n \"\$TMPDIR\"" \
698
- " set _valise_fish_persistence_tmp_parent \"\$TMPDIR\"" \
699
- "end" \
700
- "set _valise_fish_persistence_tmp_parent (builtin path resolve -- \"\$_valise_fish_persistence_tmp_parent\" 2>/dev/null)" \
701
- "if test (builtin count \$_valise_fish_persistence_tmp_parent) -ne 1; or not test -d \"\$_valise_fish_persistence_tmp_parent\"; or not test -w \"\$_valise_fish_persistence_tmp_parent\"; or not test -x \"\$_valise_fish_persistence_tmp_parent\"" \
702
- " builtin exit 125" \
703
- "end" \
704
- "# Capture persistent SHELL_PROJECT_ROOT scopes before clearing activation state." \
705
- "set -l _valise_fish_scratch_names _valise_fish_root_global_set _valise_fish_root_global_exported _valise_fish_root_global_values _valise_fish_root_universal_set _valise_fish_root_universal_exported _valise_fish_root_universal_values VALISE_MODULE_ROOT XDG_CONFIG_HOME TMPDIR HOME" \
706
- "set -l _valise_fish_scratch_prefix __valise_fish_scratch_state_(builtin random)" \
707
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_set_global_present" \
708
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_set_global_exported" \
709
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_set_global_values" \
710
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_set_universal_present" \
711
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_set_universal_exported" \
712
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_set_universal_values" \
713
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_exported_global_present" \
714
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_exported_global_exported" \
715
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_exported_global_values" \
716
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_exported_universal_present" \
717
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_exported_universal_exported" \
718
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_exported_universal_values" \
719
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_values_global_present" \
720
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_values_global_exported" \
721
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_values_global_values" \
722
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_values_universal_present" \
723
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_values_universal_exported" \
724
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_global_values_universal_values" \
725
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_set_global_present" \
726
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_set_global_exported" \
727
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_set_global_values" \
728
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_set_universal_present" \
729
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_set_universal_exported" \
730
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_set_universal_values" \
731
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_exported_global_present" \
732
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_exported_global_exported" \
733
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_exported_global_values" \
734
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_exported_universal_present" \
735
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_exported_universal_exported" \
736
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_exported_universal_values" \
737
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_values_global_present" \
738
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_values_global_exported" \
739
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_values_global_values" \
740
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_values_universal_present" \
741
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_values_universal_exported" \
742
- "set -l \"\$_valise_fish_scratch_prefix\"__valise_fish_root_universal_values_universal_values" \
743
- "set -l \"\$_valise_fish_scratch_prefix\"_VALISE_MODULE_ROOT_global_present" \
744
- "set -l \"\$_valise_fish_scratch_prefix\"_VALISE_MODULE_ROOT_global_exported" \
745
- "set -l \"\$_valise_fish_scratch_prefix\"_VALISE_MODULE_ROOT_global_values" \
746
- "set -l \"\$_valise_fish_scratch_prefix\"_VALISE_MODULE_ROOT_universal_present" \
747
- "set -l \"\$_valise_fish_scratch_prefix\"_VALISE_MODULE_ROOT_universal_exported" \
748
- "set -l \"\$_valise_fish_scratch_prefix\"_VALISE_MODULE_ROOT_universal_values" \
749
- "set -l \"\$_valise_fish_scratch_prefix\"_XDG_CONFIG_HOME_global_present" \
750
- "set -l \"\$_valise_fish_scratch_prefix\"_XDG_CONFIG_HOME_global_exported" \
751
- "set -l \"\$_valise_fish_scratch_prefix\"_XDG_CONFIG_HOME_global_values" \
752
- "set -l \"\$_valise_fish_scratch_prefix\"_XDG_CONFIG_HOME_universal_present" \
753
- "set -l \"\$_valise_fish_scratch_prefix\"_XDG_CONFIG_HOME_universal_exported" \
754
- "set -l \"\$_valise_fish_scratch_prefix\"_XDG_CONFIG_HOME_universal_values" \
755
- "set -l \"\$_valise_fish_scratch_prefix\"_TMPDIR_global_present" \
756
- "set -l \"\$_valise_fish_scratch_prefix\"_TMPDIR_global_exported" \
757
- "set -l \"\$_valise_fish_scratch_prefix\"_TMPDIR_global_values" \
758
- "set -l \"\$_valise_fish_scratch_prefix\"_TMPDIR_universal_present" \
759
- "set -l \"\$_valise_fish_scratch_prefix\"_TMPDIR_universal_exported" \
760
- "set -l \"\$_valise_fish_scratch_prefix\"_TMPDIR_universal_values" \
761
- "set -l \"\$_valise_fish_scratch_prefix\"_HOME_global_present" \
762
- "set -l \"\$_valise_fish_scratch_prefix\"_HOME_global_exported" \
763
- "set -l \"\$_valise_fish_scratch_prefix\"_HOME_global_values" \
764
- "set -l \"\$_valise_fish_scratch_prefix\"_HOME_universal_present" \
765
- "set -l \"\$_valise_fish_scratch_prefix\"_HOME_universal_exported" \
766
- "set -l \"\$_valise_fish_scratch_prefix\"_HOME_universal_values" \
767
- "set -l _valise_fish_scratch_capture_helper __valise_fish_scratch_capture_(builtin random)" \
768
- "function \$_valise_fish_scratch_capture_helper --no-scope-shadowing" \
769
- " set -l _scratch_target \$argv[1]" \
770
- " set -l _scratch_prefix \$argv[2]_\$_scratch_target" \
771
- " set -l _scratch_global_present 0" \
772
- " builtin set -q -g \"\$_scratch_target\"; and set _scratch_global_present 1" \
773
- " set -l _scratch_global_exported 0" \
774
- " builtin set -q -gx \"\$_scratch_target\"; and set _scratch_global_exported 1" \
775
- " set -l _scratch_global_values" \
776
- " if test \$_scratch_global_present -eq 1" \
777
- " set _scratch_global_values \$\$_scratch_target" \
778
- " end" \
779
- " set -l _scratch_universal_present 0" \
780
- " builtin set -q -U \"\$_scratch_target\"; and set _scratch_universal_present 1" \
781
- " set -l _scratch_universal_exported 0" \
782
- " builtin set -q -Ux \"\$_scratch_target\"; and set _scratch_universal_exported 1" \
783
- " set -l _scratch_universal_values" \
784
- " if test \$_scratch_universal_present -eq 1" \
785
- " if test \$_scratch_global_present -eq 1" \
786
- " builtin set -e -g \"\$_scratch_target\"" \
787
- " set _scratch_universal_values \$\$_scratch_target" \
788
- " if test \$_scratch_global_exported -eq 1" \
789
- " builtin set -gx \"\$_scratch_target\" \$\$_scratch_global_values" \
790
- " else" \
791
- " builtin set -g \"\$_scratch_target\" \$\$_scratch_global_values" \
792
- " end" \
793
- " else" \
794
- " set _scratch_universal_values \$\$_scratch_target" \
795
- " end" \
796
- " end" \
797
- " set \"\$_scratch_prefix\"_global_present \$_scratch_global_present" \
798
- " set \"\$_scratch_prefix\"_global_exported \$_scratch_global_exported" \
799
- " set \"\$_scratch_prefix\"_global_values \$_scratch_global_values" \
800
- " set \"\$_scratch_prefix\"_universal_present \$_scratch_universal_present" \
801
- " set \"\$_scratch_prefix\"_universal_exported \$_scratch_universal_exported" \
802
- " set \"\$_scratch_prefix\"_universal_values \$_scratch_universal_values" \
803
- "end" \
804
- "\$_valise_fish_scratch_capture_helper _valise_fish_root_global_set \"\$_valise_fish_scratch_prefix\"" \
805
- "\$_valise_fish_scratch_capture_helper _valise_fish_root_global_exported \"\$_valise_fish_scratch_prefix\"" \
806
- "\$_valise_fish_scratch_capture_helper _valise_fish_root_global_values \"\$_valise_fish_scratch_prefix\"" \
807
- "\$_valise_fish_scratch_capture_helper _valise_fish_root_universal_set \"\$_valise_fish_scratch_prefix\"" \
808
- "\$_valise_fish_scratch_capture_helper _valise_fish_root_universal_exported \"\$_valise_fish_scratch_prefix\"" \
809
- "\$_valise_fish_scratch_capture_helper _valise_fish_root_universal_values \"\$_valise_fish_scratch_prefix\"" \
810
- "\$_valise_fish_scratch_capture_helper VALISE_MODULE_ROOT \"\$_valise_fish_scratch_prefix\"" \
811
- "\$_valise_fish_scratch_capture_helper XDG_CONFIG_HOME \"\$_valise_fish_scratch_prefix\"" \
812
- "\$_valise_fish_scratch_capture_helper TMPDIR \"\$_valise_fish_scratch_prefix\"" \
813
- "\$_valise_fish_scratch_capture_helper HOME \"\$_valise_fish_scratch_prefix\"" \
814
- "builtin functions -e \$_valise_fish_scratch_capture_helper 2>/dev/null" \
815
- "set -l _valise_fish_root_global_set 0" \
816
- "set -l _valise_fish_root_global_exported 0" \
817
- "set -l _valise_fish_root_global_values" \
818
- "set -l _valise_fish_root_universal_set 0" \
819
- "set -l _valise_fish_root_universal_exported 0" \
820
- "set -l _valise_fish_root_universal_values" \
821
- "set -l _valise_fish_root_capture_helper __valise_fish_capture_(builtin random)" \
822
- "function \$_valise_fish_root_capture_helper --no-scope-shadowing" \
823
- " set _valise_fish_root_global_set 0" \
824
- " set _valise_fish_root_global_exported 0" \
825
- " set _valise_fish_root_global_values" \
826
- " set _valise_fish_root_universal_set 0" \
827
- " set _valise_fish_root_universal_exported 0" \
828
- " set _valise_fish_root_universal_values" \
829
- " if builtin set -q -g SHELL_PROJECT_ROOT" \
830
- " set _valise_fish_root_global_set 1" \
831
- " builtin set -q -gx SHELL_PROJECT_ROOT; and set _valise_fish_root_global_exported 1" \
832
- " set _valise_fish_root_global_values \$SHELL_PROJECT_ROOT" \
833
- " end" \
834
- " if builtin set -q -U SHELL_PROJECT_ROOT" \
835
- " set _valise_fish_root_universal_set 1" \
836
- " builtin set -q -Ux SHELL_PROJECT_ROOT; and set _valise_fish_root_universal_exported 1" \
837
- " if builtin test \$_valise_fish_root_global_set -eq 1" \
838
- " builtin set -e -g SHELL_PROJECT_ROOT; or builtin exit 125" \
839
- " set _valise_fish_root_universal_values \$SHELL_PROJECT_ROOT" \
840
- " if builtin test \$_valise_fish_root_global_exported -eq 1" \
841
- " builtin set -gx SHELL_PROJECT_ROOT \$_valise_fish_root_global_values; or builtin exit 125" \
842
- " else" \
843
- " builtin set -g SHELL_PROJECT_ROOT \$_valise_fish_root_global_values; or builtin exit 125" \
844
- " end" \
845
- " else" \
846
- " set _valise_fish_root_universal_values \$SHELL_PROJECT_ROOT" \
847
- " end" \
848
- " end" \
849
- "end" \
850
- "\$_valise_fish_root_capture_helper" \
851
- "builtin functions -e \$_valise_fish_root_capture_helper" \
852
- "set -l _valise_fish_scratch_restore_helper __valise_fish_scratch_restore_(builtin random)" \
853
- "function \$_valise_fish_scratch_restore_helper --no-scope-shadowing" \
854
- " set -l _scratch_target \$argv[1]" \
855
- " set -l _scratch_prefix \$argv[2]_\$_scratch_target" \
856
- " set -l _scratch_global_present_var \"\$_scratch_prefix\"_global_present" \
857
- " set -l _scratch_global_exported_var \"\$_scratch_prefix\"_global_exported" \
858
- " set -l _scratch_global_values_var \"\$_scratch_prefix\"_global_values" \
859
- " set -l _scratch_universal_present_var \"\$_scratch_prefix\"_universal_present" \
860
- " set -l _scratch_universal_exported_var \"\$_scratch_prefix\"_universal_exported" \
861
- " set -l _scratch_universal_values_var \"\$_scratch_prefix\"_universal_values" \
862
- " if builtin set -q -g \"\$_scratch_target\"" \
863
- " builtin set -e -g \"\$_scratch_target\"; or return 125" \
864
- " end" \
865
- " if builtin set -q -U \"\$_scratch_target\"" \
866
- " builtin set -e -U \"\$_scratch_target\"; or return 125" \
867
- " end" \
868
- " if test \$\$_scratch_global_present_var -eq 1" \
869
- " set -l _scratch_global_flags -g" \
870
- " if test \$\$_scratch_global_exported_var -eq 1" \
871
- " set _scratch_global_flags -gx" \
872
- " end" \
873
- " builtin set \$_scratch_global_flags \"\$_scratch_target\" \$\$_scratch_global_values_var" \
874
- " if test \$status -ne 0" \
875
- " return 125" \
876
- " end" \
877
- " end" \
878
- " if test \$\$_scratch_universal_present_var -eq 1" \
879
- " set -l _scratch_universal_flags -U" \
880
- " if test \$\$_scratch_universal_exported_var -eq 1" \
881
- " set _scratch_universal_flags -Ux" \
882
- " end" \
883
- " builtin set \$_scratch_universal_flags \"\$_scratch_target\" \$\$_scratch_universal_values_var" \
884
- " if test \$status -ne 0" \
885
- " return 125" \
886
- " end" \
887
- " end" \
888
- " if test \"\$_scratch_target\" = VALISE_MODULE_ROOT; or test \"\$_scratch_target\" = XDG_CONFIG_HOME; or test \"\$_scratch_target\" = TMPDIR; or test \"\$_scratch_target\" = HOME" \
889
- " if not builtin functions -q \$_valise_fish_persistence_verify_helper; or not builtin test (builtin functions \$_valise_fish_persistence_verify_helper | string collect) = \"\$_valise_fish_persistence_helper_definition\"" \
890
- " builtin printf '%s\\n' 'trusted universal persistence verifier was modified' >&2" \
891
- " return 125" \
892
- " end" \
893
- " \$_valise_fish_persistence_verify_helper \"\$_valise_fish_persistence_durable_file\" \"\$_valise_fish_persistence_tmp_parent\" \"\$_scratch_target\" \"\$\$_scratch_universal_present_var\" \"\$\$_scratch_universal_exported_var\" \$\$_scratch_universal_values_var; or return 125" \
894
- " end" \
895
- " for _scratch_suffix in global_present global_exported global_values universal_present universal_exported universal_values" \
896
- " set -l _scratch_snapshot_name \"\$_scratch_prefix\"_\$_scratch_suffix" \
897
- " if builtin set -q -l \"\$_scratch_snapshot_name\"" \
898
- " builtin set -e -l \"\$_scratch_snapshot_name\"; or return 125" \
899
- " end" \
900
- " if builtin set -q -g \"\$_scratch_snapshot_name\"" \
901
- " builtin set -e -g \"\$_scratch_snapshot_name\"; or return 125" \
902
- " end" \
903
- " if builtin set -q -U \"\$_scratch_snapshot_name\"" \
904
- " builtin set -e -U \"\$_scratch_snapshot_name\"; or return 125" \
905
- " end" \
906
- " end" \
907
- "end" \
908
- "set -l _valise_fish_persistence_verify_helper __valise_fish_verify_(builtin random)" \
909
- "function \$_valise_fish_persistence_verify_helper --no-scope-shadowing" \
910
- " set -l _persistence_durable_file \$argv[1]" \
911
- " set -l _persistence_tmp_parent \$argv[2]" \
912
- " set -l _persistence_scope \$argv[3]" \
913
- " set -l _persistence_expected_present \$argv[4]" \
914
- " set -l _persistence_expected_exported \$argv[5]" \
915
- " set -l _persistence_expected_values \$argv[6..-1]" \
916
- " set -l _persistence_fish_path (status fish-path)" \
917
- " if test (builtin count \$_persistence_fish_path) -ne 1; or not test -x \"\$_persistence_fish_path\"" \
918
- " return 125" \
919
- " end" \
920
- " # _persistence_durable_file was captured before untrusted source execution." \
921
- " if not test -f \"\$_persistence_durable_file\"" \
922
- " if test \"\$_persistence_expected_present\" = 0" \
923
- " return 0" \
924
- " end" \
925
- " return 125" \
926
- " end" \
927
- " if not string match -q '/*' -- \"\$_persistence_tmp_parent\"; or not test -d \"\$_persistence_tmp_parent\"; or not test -w \"\$_persistence_tmp_parent\"; or not test -x \"\$_persistence_tmp_parent\"" \
928
- " return 125" \
929
- " end" \
930
- " set -l _persistence_checked_file \$_persistence_durable_file" \
931
- " if test -x /usr/bin/uname; and test (/usr/bin/uname -s 2>/dev/null) = Darwin" \
932
- " if builtin test -L /var; and test (builtin path resolve -- /var 2>/dev/null) = /private/var" \
933
- " set _persistence_checked_file (builtin string replace -r '^/var' /private/var -- \"\$_persistence_checked_file\")" \
934
- " end" \
935
- " if builtin test -L /tmp; and test (builtin path resolve -- /tmp 2>/dev/null) = /private/tmp" \
936
- " set _persistence_checked_file (builtin string replace -r '^/tmp' /private/tmp -- \"\$_persistence_checked_file\")" \
937
- " end" \
938
- " end" \
939
- " if not builtin string match -q '/*' -- \"\$_persistence_checked_file\"; or builtin string match -q '*//*' -- \"\$_persistence_checked_file\"" \
940
- " return 125" \
941
- " end" \
942
- " set -l _persistence_checked_prefix /" \
943
- " for _persistence_checked_component in (builtin string split '/' -- \"\$_persistence_checked_file\")" \
944
- " if test -z \"\$_persistence_checked_component\"" \
945
- " continue" \
946
- " end" \
947
- " switch \"\$_persistence_checked_component\"" \
948
- " case . .." \
949
- " return 125" \
950
- " end" \
951
- " if test \"\$_persistence_checked_prefix\" = /" \
952
- " set _persistence_checked_prefix /\$_persistence_checked_component" \
953
- " else" \
954
- " set _persistence_checked_prefix \"\$_persistence_checked_prefix/\$_persistence_checked_component\"" \
955
- " end" \
956
- " if builtin test -L \"\$_persistence_checked_prefix\"" \
957
- " return 125" \
958
- " end" \
959
- " end" \
960
- " set -e _persistence_checked_file _persistence_checked_prefix _persistence_checked_component" \
961
- " set -l _persistence_mktemp_path ''" \
962
- " for _persistence_candidate in /usr/bin/mktemp /bin/mktemp" \
963
- " if test -x \"\$_persistence_candidate\"" \
964
- " set _persistence_mktemp_path \"\$_persistence_candidate\"" \
965
- " break" \
966
- " end" \
967
- " end" \
968
- " set -l _persistence_mkdir_path ''" \
969
- " for _persistence_candidate in /bin/mkdir /usr/bin/mkdir" \
970
- " if test -x \"\$_persistence_candidate\"" \
971
- " set _persistence_mkdir_path \"\$_persistence_candidate\"" \
972
- " break" \
973
- " end" \
974
- " end" \
975
- " set -l _persistence_ln_path ''" \
976
- " for _persistence_candidate in /bin/ln /usr/bin/ln" \
977
- " if test -x \"\$_persistence_candidate\"" \
978
- " set _persistence_ln_path \"\$_persistence_candidate\"" \
979
- " break" \
980
- " end" \
981
- " end" \
982
- " set -l _persistence_rm_path ''" \
983
- " for _persistence_candidate in /bin/rm /usr/bin/rm" \
984
- " if test -x \"\$_persistence_candidate\"" \
985
- " set _persistence_rm_path \"\$_persistence_candidate\"" \
986
- " break" \
987
- " end" \
988
- " end" \
989
- " if test -z \"\$_persistence_mktemp_path\"; or test -z \"\$_persistence_mkdir_path\"; or test -z \"\$_persistence_ln_path\"; or test -z \"\$_persistence_rm_path\"" \
990
- " return 125" \
991
- " end" \
992
- " set -l _persistence_verify_root (\"\$_persistence_mktemp_path\" -d \"\$_persistence_tmp_parent/valise-fish-persistence.XXXXXX\" 2>/dev/null)" \
993
- " if test \$status -ne 0; or test (builtin count \$_persistence_verify_root) -ne 1" \
994
- " return 125" \
995
- " end" \
996
- " if not \"\$_persistence_mkdir_path\" -p \"\$_persistence_verify_root/fish\"; or not \"\$_persistence_ln_path\" -s \"\$_persistence_durable_file\" \"\$_persistence_verify_root/fish/fish_variables\"" \
997
- " if not \"\$_persistence_rm_path\" -rf -- \"\$_persistence_verify_root\" 2>/dev/null" \
998
- " return 125" \
999
- " end" \
1000
- " return 125" \
1001
- " end" \
1002
- " set -lx XDG_CONFIG_HOME \"\$_persistence_verify_root\"" \
1003
- " set -l _persistence_actual (\"\$_persistence_fish_path\" -c '" \
1004
- " set -l _persistence_name \$argv[1]" \
1005
- " # Remove an inherited global shadow before reading the universal store." \
1006
- " if builtin set -q -g -- \$_persistence_name" \
1007
- " set -l _persistence_global_values \$\$_persistence_name" \
1008
- " builtin set -e -g -- \$_persistence_name; or exit 125" \
1009
- " end" \
1010
- " if builtin set -q -U -- \$_persistence_name" \
1011
- " builtin printf \"1\\n\"" \
1012
- " if builtin set -q -Ux -- \$_persistence_name" \
1013
- " builtin printf \"1\\n\"" \
1014
- " else" \
1015
- " builtin printf \"0\\n\"" \
1016
- " end" \
1017
- " string escape -- \$\$_persistence_name" \
1018
- " else" \
1019
- " builtin printf \"0\\n0\\n\"" \
1020
- " end" \
1021
- " ' -- \"\$_persistence_scope\" 2>/dev/null)" \
1022
- " set -l _persistence_child_status \$status" \
1023
- " if not \"\$_persistence_rm_path\" -rf -- \"\$_persistence_verify_root\" 2>/dev/null" \
1024
- " return 125" \
1025
- " end" \
1026
- " if test \$_persistence_child_status -ne 0" \
1027
- " return 125" \
1028
- " end" \
1029
- " set -l _persistence_expected \$_persistence_expected_present \$_persistence_expected_exported" \
1030
- " set -a _persistence_expected (string escape -- \$_persistence_expected_values)" \
1031
- " if test (builtin count \$_persistence_actual) -ne (builtin count \$_persistence_expected)" \
1032
- " return 125" \
1033
- " end" \
1034
- " set -l _persistence_index 1" \
1035
- " while test \$_persistence_index -le (builtin count \$_persistence_expected)" \
1036
- " if not builtin test \"\$_persistence_actual[\$_persistence_index]\" = \"\$_persistence_expected[\$_persistence_index]\"" \
1037
- " return 125" \
1038
- " end" \
1039
- " set _persistence_index (builtin math \$_persistence_index + 1)" \
1040
- " end" \
1041
- " return 0" \
1042
- "end" \
1043
- "# Restore persistent caller root scopes and remove the temporary snapshot state." \
1044
- "set -l _valise_fish_root_restore_helper __valise_fish_restore_(builtin random)" \
1045
- "function \$_valise_fish_root_restore_helper --no-scope-shadowing" \
1046
- " if builtin set -q -g SHELL_PROJECT_ROOT" \
1047
- " builtin set -e -g SHELL_PROJECT_ROOT; or return 125" \
1048
- " end" \
1049
- " if builtin set -q -U SHELL_PROJECT_ROOT" \
1050
- " builtin set -e -U SHELL_PROJECT_ROOT; or return 125" \
1051
- " end" \
1052
- " if builtin test \$_valise_fish_root_global_set -eq 1" \
1053
- " set -l _valise_fish_root_global_flags -g" \
1054
- " if builtin test \$_valise_fish_root_global_exported -eq 1" \
1055
- " set _valise_fish_root_global_flags -gx" \
1056
- " end" \
1057
- " builtin set \$_valise_fish_root_global_flags SHELL_PROJECT_ROOT \$_valise_fish_root_global_values" \
1058
- " if test \$status -ne 0" \
1059
- " return 125" \
1060
- " end" \
1061
- " end" \
1062
- " if not builtin functions -q \$_valise_fish_persistence_verify_helper; or not builtin test (builtin functions \$_valise_fish_persistence_verify_helper | string collect) = \"\$_valise_fish_persistence_helper_definition\"" \
1063
- " builtin printf '%s\\n' 'trusted universal persistence verifier was modified' >&2" \
1064
- " return 125" \
1065
- " end" \
1066
- " if builtin test \$_valise_fish_root_universal_set -eq 1" \
1067
- " set -l _valise_fish_root_universal_flags -U" \
1068
- " if builtin test \$_valise_fish_root_universal_exported -eq 1" \
1069
- " set _valise_fish_root_universal_flags -Ux" \
1070
- " end" \
1071
- " builtin set \$_valise_fish_root_universal_flags SHELL_PROJECT_ROOT \$_valise_fish_root_universal_values" \
1072
- " if test \$status -ne 0" \
1073
- " return 125" \
1074
- " end" \
1075
- " end" \
1076
- " \$_valise_fish_persistence_verify_helper \"\$_valise_fish_persistence_durable_file\" \"\$_valise_fish_persistence_tmp_parent\" SHELL_PROJECT_ROOT \"\$_valise_fish_root_universal_set\" \"\$_valise_fish_root_universal_exported\" \$_valise_fish_root_universal_values; or return 125" \
1077
- " for _valise_fish_root_state in _valise_fish_root_global_set _valise_fish_root_global_exported _valise_fish_root_global_values _valise_fish_root_universal_set _valise_fish_root_universal_exported _valise_fish_root_universal_values" \
1078
- " if builtin set -q -l \$_valise_fish_root_state" \
1079
- " builtin set -e -l \$_valise_fish_root_state; or return 125" \
1080
- " end" \
1081
- " end" \
1082
- " for _valise_fish_scratch_name in \$_valise_fish_scratch_names" \
1083
- " if not builtin functions -q \$_valise_fish_scratch_restore_helper; or not builtin test (builtin functions \$_valise_fish_scratch_restore_helper | string collect) = \"\$_valise_fish_scratch_helper_definition\"" \
1084
- " builtin printf '%s\\n' 'trusted scratch restore helper was modified' >&2" \
1085
- " builtin exit 125" \
1086
- " end" \
1087
- " \$_valise_fish_scratch_restore_helper \"\$_valise_fish_scratch_name\" \"\$_valise_fish_scratch_prefix\"; or return 125" \
1088
- " end" \
1089
- " if builtin set -q _valise_fish_persistence_verify_helper; and builtin functions -q \"\$_valise_fish_persistence_verify_helper\"" \
1090
- " builtin functions -e \"\$_valise_fish_persistence_verify_helper\"; or return 125" \
1091
- " end" \
1092
- " builtin functions -e (builtin status function) 2>/dev/null" \
1093
- "end" \
1094
- "# Publish only the authenticated active root and readiness marker. Untrusted" \
1095
- "# source may have left universal shadows behind, so remove them before the" \
1096
- "# global public state is exposed." \
1097
- "set -l _valise_fish_publish_active_helper __valise_fish_publish_(builtin random)" \
1098
- "function \$_valise_fish_publish_active_helper --no-scope-shadowing" \
1099
- " if builtin set -q -U SHELL_PROJECT_ROOT" \
1100
- " builtin set -e -U SHELL_PROJECT_ROOT; or return 125" \
1101
- " end" \
1102
- " builtin set -gx SHELL_PROJECT_ROOT \"\$_valise_fish_active_root\"; or return 125" \
1103
- " if builtin set -q -U VALISE_FISH_READY" \
1104
- " builtin set -e -U VALISE_FISH_READY; or return 125" \
1105
- " end" \
1106
- " builtin set -gx VALISE_FISH_READY 1; or return 125" \
1107
- "end" \
1108
- "set -l _valise_fish_publish_active_helper_definition (builtin functions \"\$_valise_fish_publish_active_helper\" | string collect)" \
1109
- "# Successful activation keeps the authenticated public root/readiness state." \
1110
- "# It only removes private snapshots and trusted helper functions; rollback" \
1111
- "# is reserved for failure paths." \
1112
- "set -l _valise_fish_success_cleanup_helper __valise_fish_cleanup_(builtin random)" \
1113
- "function \$_valise_fish_success_cleanup_helper --no-scope-shadowing" \
1114
- " if not builtin functions -q \$_valise_fish_success_cleanup_helper; or not builtin test (builtin functions \$_valise_fish_success_cleanup_helper | string collect) = \"\$_valise_fish_success_cleanup_helper_definition\"" \
1115
- " builtin printf '%s\\n' 'trusted success cleanup helper was modified' >&2" \
1116
- " return 125" \
1117
- " end" \
1118
- " for _valise_fish_root_state in _valise_fish_root_global_set _valise_fish_root_global_exported _valise_fish_root_global_values _valise_fish_root_universal_set _valise_fish_root_universal_exported _valise_fish_root_universal_values" \
1119
- " if builtin set -q -l \$_valise_fish_root_state" \
1120
- " builtin set -e -l \$_valise_fish_root_state; or return 125" \
1121
- " end" \
1122
- " end" \
1123
- " if not builtin functions -q \$_valise_fish_scratch_restore_helper; or not builtin test (builtin functions \$_valise_fish_scratch_restore_helper | string collect) = \"\$_valise_fish_scratch_restore_helper_definition\"" \
1124
- " builtin printf '%s\\n' 'trusted scratch restore helper was modified' >&2" \
1125
- " return 125" \
1126
- " end" \
1127
- " for _valise_fish_scratch_name in \$_valise_fish_scratch_names" \
1128
- " if not builtin functions -q \$_valise_fish_scratch_restore_helper; or not builtin test (builtin functions \$_valise_fish_scratch_restore_helper | string collect) = \"\$_valise_fish_scratch_helper_definition\"" \
1129
- " builtin printf '%s\\n' 'trusted scratch restore helper was modified' >&2" \
1130
- " return 125" \
1131
- " end" \
1132
- " \$_valise_fish_scratch_restore_helper \"\$_valise_fish_scratch_name\" \"\$_valise_fish_scratch_prefix\"; or return 125" \
1133
- " end" \
1134
- " if builtin set -q _valise_fish_publish_active_helper; and builtin functions -q \"\$_valise_fish_publish_active_helper\"" \
1135
- " if not builtin test (builtin functions \"\$_valise_fish_publish_active_helper\" | string collect) = \"\$_valise_fish_publish_active_helper_definition\"" \
1136
- " builtin printf '%s\\n' 'trusted active-state publisher was modified' >&2" \
1137
- " return 125" \
1138
- " end" \
1139
- " builtin functions -e \"\$_valise_fish_publish_active_helper\"; or return 125" \
1140
- " end" \
1141
- " if builtin set -q _valise_fish_persistence_verify_helper; and builtin functions -q \"\$_valise_fish_persistence_verify_helper\"" \
1142
- " if not builtin test (builtin functions \"\$_valise_fish_persistence_verify_helper\" | string collect) = \"\$_valise_fish_persistence_helper_definition\"" \
1143
- " builtin printf '%s\\n' 'trusted universal persistence verifier was modified' >&2" \
1144
- " return 125" \
1145
- " end" \
1146
- " builtin functions -e \"\$_valise_fish_persistence_verify_helper\"; or return 125" \
1147
- " end" \
1148
- " if builtin functions -q \"\$_valise_fish_root_restore_helper\"" \
1149
- " if not builtin test (builtin functions \"\$_valise_fish_root_restore_helper\" | string collect) = \"\$_valise_fish_root_helper_definition\"" \
1150
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
1151
- " return 125" \
1152
- " end" \
1153
- " builtin functions -e \"\$_valise_fish_root_restore_helper\"; or return 125" \
1154
- " end" \
1155
- " if builtin functions -q \"\$_valise_fish_scratch_restore_helper\"" \
1156
- " if not builtin test (builtin functions \"\$_valise_fish_scratch_restore_helper\" | string collect) = \"\$_valise_fish_scratch_restore_helper_definition\"" \
1157
- " builtin printf '%s\\n' 'trusted scratch restore helper was modified' >&2" \
1158
- " return 125" \
1159
- " end" \
1160
- " builtin functions -e \"\$_valise_fish_scratch_restore_helper\"; or return 125" \
1161
- " end" \
1162
- " builtin functions -e (builtin status function) 2>/dev/null; or return 125" \
1163
- "end" \
1164
- "# Keep cleanup definitions outside the Fish function namespace while" \
1165
- "# untrusted entrypoints and generated plans are executing. Function names" \
1166
- "# are enumerable, so the trusted definitions stay in caller-local Fish" \
1167
- "# variables rather than same-user-writable temporary files." \
1168
- "set -l _valise_fish_root_helper_definition (builtin functions \"\$_valise_fish_root_restore_helper\" | string collect)" \
1169
- "set -l _valise_fish_success_cleanup_helper_definition (builtin functions \"\$_valise_fish_success_cleanup_helper\" | string collect)" \
1170
- "set -l _valise_fish_persistence_helper_definition (builtin functions \"\$_valise_fish_persistence_verify_helper\" | string collect)" \
1171
- "set -l _valise_fish_scratch_helper_definition (builtin functions \"\$_valise_fish_scratch_restore_helper\" | string collect)" \
1172
- "set -l _valise_fish_scratch_restore_helper_definition (builtin functions \"\$_valise_fish_scratch_restore_helper\" | string collect)" \
1173
- "if test (builtin count \$_valise_fish_root_helper_definition) -ne 1; or test (builtin count \$_valise_fish_success_cleanup_helper_definition) -ne 1; or test (builtin count \$_valise_fish_publish_active_helper_definition) -ne 1; or test (builtin count \$_valise_fish_persistence_helper_definition) -ne 1; or test (builtin count \$_valise_fish_scratch_helper_definition) -ne 1; or test (builtin count \$_valise_fish_scratch_restore_helper_definition) -ne 1" \
1174
- " printf '%s\\n' 'valise Fish integration: trusted cleanup snapshot unavailable' >&2" \
1175
- " return 125" \
1176
- "end" \
1177
- "# Activate one historical generated Fish plan transactionally." \
1178
- "set -l _valise_fish_legacy_runner __valise_fish_legacy_run_(builtin random)" \
1179
- "function \$_valise_fish_legacy_runner" \
1180
- " set -l _legacy_root \$argv[1]" \
1181
- " set -l _legacy_plan \$argv[2]" \
1182
- " set -l _legacy_before (builtin functions --all --names)" \
1183
- " set -l _legacy_snapshot_names" \
1184
- " set -l _legacy_snapshot_definitions" \
1185
- " set -l _legacy_runner_name (builtin status function)" \
1186
- " set -l _legacy_snapshot_index 1" \
1187
- " set -l _legacy_critical_names contains test string source path functions set printf echo math count eval cd pwd" \
1188
- " set -l _legacy_snapshot_sources" \
1189
- " for _legacy_function in \$_legacy_before" \
1190
- " if builtin contains -- \"\$_legacy_function\" \"\$_legacy_runner_name\"; or not builtin functions -q \"\$_legacy_function\"" \
1191
- " continue" \
1192
- " end" \
1193
- " set -l _legacy_source (builtin functions --details \"\$_legacy_function\")" \
1194
- " if not builtin contains -- \"\$_legacy_function\" \$_legacy_critical_names; and builtin string match -q -r '^(embedded:|autoloaded:|builtin)' -- \"\$_legacy_source\"" \
1195
- " continue" \
1196
- " end" \
1197
- " set -l _legacy_definition (builtin functions \"\$_legacy_function\" | string collect)" \
1198
- " if test (builtin count \$_legacy_definition) -ne 1" \
1199
- " builtin printf 'valise Fish integration: unable to snapshot caller Fish function: %s\\n' \"\$_legacy_function\" >&2" \
1200
- " return 1" \
1201
- " end" \
1202
- " set -a _legacy_snapshot_names \"\$_legacy_function\"" \
1203
- " set -a _legacy_snapshot_definitions \"\$_legacy_definition\"" \
1204
- " set -a _legacy_snapshot_sources \"\$_legacy_source\"" \
1205
- " set _legacy_snapshot_index (builtin math \$_legacy_snapshot_index + 1)" \
1206
- " end" \
1207
- " builtin set -gx VALISE_MODULE_ROOT \"\$_legacy_root\"" \
1208
- " set -l _legacy_source_runner __valise_fish_legacy_source_(builtin random)" \
1209
- " function \$_legacy_source_runner" \
1210
- " builtin source \"\$argv[1]\"" \
1211
- " return \$status" \
1212
- " end" \
1213
- " \$_legacy_source_runner \"\$_legacy_plan\"" \
1214
- " set -l _legacy_status \$status" \
1215
- " builtin functions -e \$_legacy_source_runner 2>/dev/null" \
1216
- " set -l _legacy_after (builtin functions --all --names)" \
1217
- " set -l _legacy_created" \
1218
- " set -l _legacy_critical_created" \
1219
- " for _legacy_function in \$_legacy_after" \
1220
- " if not builtin contains -- \"\$_legacy_function\" \$_legacy_before" \
1221
- " set -a _legacy_created \"\$_legacy_function\"" \
1222
- " if builtin contains -- \"\$_legacy_function\" \$_legacy_critical_names" \
1223
- " set -a _legacy_critical_created \"\$_legacy_function\"" \
1224
- " end" \
1225
- " end" \
1226
- " end" \
1227
- " set -l _legacy_replaced" \
1228
- " set -l _legacy_embedded_replaced" \
1229
- " set _legacy_snapshot_index 1" \
1230
- " for _legacy_original in \$_legacy_snapshot_names" \
1231
- " set -l _legacy_definition \"\$_legacy_snapshot_definitions[\$_legacy_snapshot_index]\"" \
1232
- " if not builtin functions -q \"\$_legacy_original\"; or not test (builtin functions \"\$_legacy_original\" | string collect) = \"\$_legacy_definition\"" \
1233
- " set -a _legacy_replaced \"\$_legacy_original\"" \
1234
- " if builtin string match -q 'embedded:*' -- \"\$_legacy_snapshot_sources[\$_legacy_snapshot_index]\"" \
1235
- " set -a _legacy_embedded_replaced \"\$_legacy_original\"" \
1236
- " end" \
1237
- " end" \
1238
- " set _legacy_snapshot_index (builtin math \$_legacy_snapshot_index + 1)" \
1239
- " end" \
1240
- " for _legacy_state in VALISE_FISH_READY _sp_fish_loader_expected_source _sp_fish_metadata_expected_source _sp_fish_loader_bootstrap_status _sp_fish_loader_bootstrap_mode _sp_fish_loader_bootstrap_seeds VALISE_MODULE_ROOT SHELL_PROJECT_ROOT XDG_CONFIG_HOME TMPDIR HOME" \
1241
- " if builtin set -q -g \"\$_legacy_state\"; and not builtin set -e -g \"\$_legacy_state\"; builtin exit 125; end" \
1242
- " if builtin set -q -U \"\$_legacy_state\"; and not builtin set -e -U \"\$_legacy_state\"; builtin exit 125; end" \
1243
- " end" \
1244
- " # Embedded critical replacement cannot be restored without changing Fish provenance. Fail closed before any restoration." \
1245
- " if test (builtin count \$_legacy_embedded_replaced) -ne 0; or test (builtin count \$_legacy_critical_created) -ne 0" \
1246
- " builtin printf '%s\\n' 'valise Fish integration: legacy Fish plan mutated a critical Fish function' >&2" \
1247
- " builtin exit 125" \
1248
- " end" \
1249
- " if test (builtin count \$_legacy_replaced) -ne 0" \
1250
- " builtin printf '%s\\n' 'valise Fish integration: exact caller-function restoration is unavailable' >&2" \
1251
- " builtin exit 125" \
1252
- " end" \
1253
- " if test \$_legacy_status -ne 0; or test (builtin count \$_legacy_replaced) -ne 0; or test (builtin count \$_legacy_critical_created) -ne 0;" \
1254
- " for _legacy_function in \$_legacy_created" \
1255
- " if builtin functions -q \"\$_legacy_function\"" \
1256
- " if builtin contains -- \"\$_legacy_function\" \$_legacy_critical_created; or test \$_legacy_status -ne 0; or test (builtin count \$_legacy_replaced) -ne 0" \
1257
- " builtin functions -e \"\$_legacy_function\"" \
1258
- " end" \
1259
- " end" \
1260
- " end" \
1261
- " if test (builtin count \$_legacy_embedded_replaced) -ne 0; or test (builtin count \$_legacy_critical_created) -ne 0;" \
1262
- " builtin printf '%s\\n' 'valise Fish integration: legacy Fish plan mutated a critical Fish function' >&2" \
1263
- " test \$_legacy_status -ne 0; or set _legacy_status 125" \
1264
- " else if test (builtin count \$_legacy_replaced) -ne 0" \
1265
- " builtin printf '%s\\n' 'valise Fish integration: legacy Fish plan replaced a caller-owned function' >&2" \
1266
- " test \$_legacy_status -ne 0; or set _legacy_status 1" \
1267
- " else" \
1268
- " builtin printf 'valise Fish integration: legacy Fish plan failed with status %d\\n' \$_legacy_status >&2" \
1269
- " end" \
1270
- " return \$_legacy_status" \
1271
- " end" \
1272
- " builtin set -g _sp_fish_legacy_owned_exports \$_legacy_created" \
1273
- " set -l _legacy_sources" \
1274
- " for _legacy_function in \$_legacy_created" \
1275
- " set -a _legacy_sources (builtin functions --details \"\$_legacy_function\")" \
1276
- " end" \
1277
- " builtin set -g _sp_fish_legacy_owned_sources \$_legacy_sources" \
1278
- " if not builtin set -q _sp_fish_module_roots" \
1279
- " builtin set -g _sp_fish_module_roots" \
1280
- " end" \
1281
- " builtin set -ga _sp_fish_module_roots \"\$_legacy_root\"" \
1282
- " return 0" \
1283
- "end" \
1284
- "# Clear handshake and readiness in both persistent scopes before activation." \
1285
- "for _valise_fish_state_name in VALISE_FISH_READY _sp_fish_loader_bootstrap_status _sp_fish_loader_bootstrap_mode _sp_fish_loader_bootstrap_seeds _sp_fish_loader_expected_source _sp_fish_metadata_expected_source VALISE_MODULE_ROOT" \
1286
- " if builtin set -q -g \"\$_valise_fish_state_name\"; and not builtin set -e -g \"\$_valise_fish_state_name\"; builtin exit 125; end" \
1287
- " if builtin set -q -U \"\$_valise_fish_state_name\"; and not builtin set -e -U \"\$_valise_fish_state_name\"; builtin exit 125; end" \
1288
- "end" \
1289
- "# Cleanup only functions whose exact current source matches an authenticated ownership ledger." \
1290
- "# Installed ledgers are accepted only for complete, authenticated release roots; source-tree mode is intentionally broader because it is an unauthenticated development surface." \
1291
- "set -l _valise_fish_active_root" \
1292
- "if test \"\$_valise_fish_source_tree_mode\" = 1" \
1293
- " set _valise_fish_active_root (builtin path resolve -- ${_fish_active_literal})" \
1294
- "else" \
1295
- " set _valise_fish_active_root (${_fish_cli_literal} verify-active --print-root 2>/dev/null)" \
1296
- "end" \
1297
- "set -l _valise_fish_owned_cleanup __valise_fish_owned_cleanup_(builtin random)" \
1298
- "function \$_valise_fish_owned_cleanup --no-scope-shadowing" \
1299
- " set -l _valise_fish_trusted_root \$_valise_fish_active_root" \
1300
- " set -l _valise_fish_ledger_invalid 0" \
1301
- " builtin test -n \"\$_valise_fish_trusted_root\"; or set _valise_fish_ledger_invalid 1" \
1302
- " for _valise_fish_ledger_name in _sp_fish_loader_owned_exports _sp_fish_legacy_owned_exports _sp_fish_metadata_owned_exports _sp_fish_entrypoint_owned_exports" \
1303
- " set -l _valise_fish_source_ledger_name ''" \
1304
- " switch \"\$_valise_fish_ledger_name\"" \
1305
- " case _sp_fish_loader_owned_exports" \
1306
- " set _valise_fish_source_ledger_name _sp_fish_loader_owned_sources" \
1307
- " case _sp_fish_legacy_owned_exports" \
1308
- " set _valise_fish_source_ledger_name _sp_fish_legacy_owned_sources" \
1309
- " case _sp_fish_metadata_owned_exports" \
1310
- " set _valise_fish_source_ledger_name _sp_fish_metadata_owned_sources" \
1311
- " case _sp_fish_entrypoint_owned_exports" \
1312
- " set _valise_fish_source_ledger_name _sp_fish_entrypoint_owned_sources" \
1313
- " end" \
1314
- " set -l _valise_fish_ledger_present 0" \
1315
- " set -l _valise_fish_source_present 0" \
1316
- " builtin set -q \$_valise_fish_ledger_name; and set _valise_fish_ledger_present 1" \
1317
- " builtin set -q \$_valise_fish_source_ledger_name; and set _valise_fish_source_present 1" \
1318
- " if builtin test \$_valise_fish_ledger_present -ne \$_valise_fish_source_present" \
1319
- " set _valise_fish_ledger_invalid 1" \
1320
- " else if builtin test \$_valise_fish_ledger_present -eq 1" \
1321
- " set -l _valise_fish_owned_names \$\$_valise_fish_ledger_name" \
1322
- " set -l _valise_fish_owned_sources \$\$_valise_fish_source_ledger_name" \
1323
- " if builtin test (builtin count \$_valise_fish_owned_names) -ne (builtin count \$_valise_fish_owned_sources)" \
1324
- " set _valise_fish_ledger_invalid 1" \
1325
- " else" \
1326
- " set -l _valise_fish_owned_index 1" \
1327
- " for _valise_fish_owned_source in \$_valise_fish_owned_sources" \
1328
- " set -l _valise_fish_source_valid 0" \
1329
- " if builtin string match -q 'embedded:*' -- \"\$_valise_fish_owned_source\"; or builtin string match -q 'autoloaded:*' -- \"\$_valise_fish_owned_source\"; or builtin string match -q 'builtin' -- \"\$_valise_fish_owned_source\"" \
1330
- " set _valise_fish_source_valid 1" \
1331
- " else if builtin test \"\$_valise_fish_source_tree_mode\" = 1; and builtin test -f \"\$_valise_fish_owned_source\"" \
1332
- " set -l _valise_fish_source_canonical (builtin path resolve -- \"\$_valise_fish_owned_source\" 2>/dev/null)" \
1333
- " if builtin string match -q \"\$_valise_fish_trusted_root/*\" -- \"\$_valise_fish_source_canonical\"" \
1334
- " set _valise_fish_source_valid 1" \
1335
- " else if builtin test -n \"\$_valise_fish_previous_root\"; and builtin string match -q \"\$_valise_fish_previous_root/*\" -- \"\$_valise_fish_source_canonical\"" \
1336
- " set _valise_fish_source_valid 1" \
1337
- " end" \
1338
- " else if builtin test \"\$_valise_fish_source_tree_mode\" != 1" \
1339
- " set -l _valise_fish_source_relative ''" \
1340
- " if builtin string match -q '*/entrypoints/fish/profile.fish' -- \"\$_valise_fish_owned_source\"" \
1341
- " set _valise_fish_source_relative entrypoints/fish/profile.fish" \
1342
- " else if builtin string match -q '*/vendor/shell-profile/lib/fish/loader.fish' -- \"\$_valise_fish_owned_source\"; or builtin string match -q '*/vendor/shell-profile/lib/fish/metadata.fish' -- \"\$_valise_fish_owned_source\"" \
1343
- " if builtin string match -q '*/loader.fish' -- \"\$_valise_fish_owned_source\"; set _valise_fish_source_relative vendor/shell-profile/lib/fish/loader.fish; else; set _valise_fish_source_relative vendor/shell-profile/lib/fish/metadata.fish; end" \
1344
- " else if builtin string match -q '*/generated/installed-modules.fish' -- \"\$_valise_fish_owned_source\"" \
1345
- " set _valise_fish_source_relative generated/installed-modules.fish" \
1346
- " end" \
1347
- " if builtin test -n \"\$_valise_fish_source_relative\"; and builtin test (builtin path resolve -- \"\$_valise_fish_owned_source\") = (builtin path resolve -- \"\$_valise_fish_trusted_root/\$_valise_fish_source_relative\")" \
1348
- " set _valise_fish_source_valid 1" \
1349
- " end" \
1350
- " end" \
1351
- " if builtin test \$_valise_fish_source_valid -ne 1" \
1352
- " set _valise_fish_ledger_invalid 1" \
1353
- " break" \
1354
- " end" \
1355
- " set _valise_fish_owned_index (builtin math \$_valise_fish_owned_index + 1)" \
1356
- " end" \
1357
- " end" \
1358
- " end" \
1359
- " end" \
1360
- " if builtin test \$_valise_fish_ledger_invalid -ne 0" \
1361
- " for _valise_fish_ledger_name in _sp_fish_loader_owned_exports _sp_fish_loader_owned_sources _sp_fish_legacy_owned_exports _sp_fish_legacy_owned_sources _sp_fish_metadata_owned_exports _sp_fish_metadata_owned_sources _sp_fish_entrypoint_owned_exports _sp_fish_entrypoint_owned_sources" \
1362
- " if builtin set -q -g \"\$_valise_fish_ledger_name\"; and not builtin set -e -g \"\$_valise_fish_ledger_name\"; builtin exit 125; end" \
1363
- " if builtin set -q -U \"\$_valise_fish_ledger_name\"; and not builtin set -e -U \"\$_valise_fish_ledger_name\"; builtin exit 125; end" \
1364
- " end" \
1365
- " builtin printf '%s\n' 'valise Fish integration: ownership ledger is not authenticated' >&2" \
1366
- " return 125" \
1367
- " end" \
1368
- " for _valise_fish_ledger_name in _sp_fish_loader_owned_exports _sp_fish_legacy_owned_exports _sp_fish_metadata_owned_exports _sp_fish_entrypoint_owned_exports" \
1369
- " set -l _valise_fish_source_ledger_name ''" \
1370
- " switch \"\$_valise_fish_ledger_name\"" \
1371
- " case _sp_fish_loader_owned_exports" \
1372
- " set _valise_fish_source_ledger_name _sp_fish_loader_owned_sources" \
1373
- " case _sp_fish_legacy_owned_exports" \
1374
- " set _valise_fish_source_ledger_name _sp_fish_legacy_owned_sources" \
1375
- " case _sp_fish_metadata_owned_exports" \
1376
- " set _valise_fish_source_ledger_name _sp_fish_metadata_owned_sources" \
1377
- " case _sp_fish_entrypoint_owned_exports" \
1378
- " set _valise_fish_source_ledger_name _sp_fish_entrypoint_owned_sources" \
1379
- " end" \
1380
- " if builtin set -q \"\$_valise_fish_ledger_name\"; and builtin set -q \"\$_valise_fish_source_ledger_name\"" \
1381
- " set -l _valise_fish_owned_index 1" \
1382
- " for _valise_fish_owned_function in \$\$_valise_fish_ledger_name" \
1383
- " set -l _valise_fish_owned_sources \$\$_valise_fish_source_ledger_name" \
1384
- " set -l _valise_fish_owned_source \$_valise_fish_owned_sources[\$_valise_fish_owned_index]" \
1385
- " if test -n \"\$_valise_fish_owned_source\"; and builtin functions -q \"\$_valise_fish_owned_function\"; and builtin test (builtin functions --details \"\$_valise_fish_owned_function\") = \"\$_valise_fish_owned_source\"" \
1386
- " builtin functions -e \"\$_valise_fish_owned_function\"; or builtin exit 125" \
1387
- " end" \
1388
- " set _valise_fish_owned_index (builtin math \$_valise_fish_owned_index + 1)" \
1389
- " end" \
1390
- " end" \
1391
- " if builtin set -q -g \"\$_valise_fish_ledger_name\"; and not builtin set -e -g \"\$_valise_fish_ledger_name\"; builtin exit 125; end" \
1392
- " if builtin set -q -U \"\$_valise_fish_ledger_name\"; and not builtin set -e -U \"\$_valise_fish_ledger_name\"; builtin exit 125; end" \
1393
- " if builtin set -q -g \"\$_valise_fish_source_ledger_name\"; and not builtin set -e -g \"\$_valise_fish_source_ledger_name\"; builtin exit 125; end" \
1394
- " if builtin set -q -U \"\$_valise_fish_source_ledger_name\"; and not builtin set -e -U \"\$_valise_fish_source_ledger_name\"; builtin exit 125; end" \
1395
- " end" \
1396
- " return 0" \
1397
- "end" \
1398
- "set -l _valise_fish_owned_cleanup_definition (builtin functions \"\$_valise_fish_owned_cleanup\" | string collect)" \
1399
- "if test (builtin count \"\$_valise_fish_owned_cleanup_definition\") -ne 1" \
1400
- " printf '%s\\n' 'valise Fish integration: trusted ownership cleanup snapshot unavailable' >&2" \
1401
- " return 125" \
1402
- "end" \
1403
- "if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
1404
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
1405
- " builtin exit 125" \
1406
- "end" \
1407
- "\$_valise_fish_owned_cleanup \"\$_valise_fish_active_root\" \"\$_valise_fish_source_tree_mode\"" \
1408
- "set -l _valise_fish_owned_cleanup_status \$status" \
1409
- "if test \$_valise_fish_owned_cleanup_status -ne 0" \
1410
- " return \$_valise_fish_owned_cleanup_status" \
1411
- "end" \
1412
- "set -l _valise_fish_legacy_activation_before (builtin functions --all --names)" \
1413
- "if test -z \"\$_valise_fish_active_root\"; or not builtin test -d \"\$_valise_fish_active_root\"" \
1414
- " printf '%s\\n' 'valise Fish integration: active release path cannot be resolved' >&2" \
1415
- " if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
1416
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
1417
- " builtin exit 125" \
1418
- " end" \
1419
- " \$_valise_fish_owned_cleanup" \
1420
- " builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
1421
- " if not builtin functions -q \$_valise_fish_root_restore_helper; or not builtin test (builtin functions \$_valise_fish_root_restore_helper | string collect) = \"\$_valise_fish_root_helper_definition\"" \
1422
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
1423
- " builtin exit 125" \
1424
- " end" \
1425
- " \$_valise_fish_root_restore_helper; or builtin exit 125" \
1426
- " return 1" \
1427
- "end" \
1428
- "if test \"\$_valise_fish_source_tree_mode\" != 1" \
1429
- " set -l _valise_fish_reverified_root (${_fish_cli_literal} verify-active --print-root 2>/dev/null)" \
1430
- " if not test -x ${_fish_cli_literal}; or not test \"\$_valise_fish_reverified_root\" = \"\$_valise_fish_active_root\"" \
1431
- " printf '%s\\n' 'valise Fish integration: active release authentication failed' >&2" \
1432
- " if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
1433
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
1434
- " builtin exit 125" \
1435
- " end" \
1436
- " \$_valise_fish_owned_cleanup" \
1437
- " if not builtin functions -q \$_valise_fish_root_restore_helper; or not builtin test (builtin functions \$_valise_fish_root_restore_helper | string collect) = \"\$_valise_fish_root_helper_definition\"" \
1438
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
1439
- " builtin exit 125" \
1440
- " end" \
1441
- " \$_valise_fish_root_restore_helper; or builtin exit 125" \
1442
- " return 1" \
1443
- " end" \
1444
- "end" \
1445
- "if test -e \"\$_valise_fish_active_root/entrypoints/fish/profile.fish\"" \
1446
- " set -l _valise_fish_entrypoint_runner __valise_fish_entrypoint_runner_(builtin random)" \
1447
- " function \$_valise_fish_entrypoint_runner" \
1448
- " set -l _entrypoint_file \$argv[1]" \
1449
- " set -l _entrypoint_expected_root \$argv[2]" \
1450
- " set -l _entrypoint_source_tree_mode \$argv[3]" \
1451
- " set -l _entrypoint_transaction_name (builtin status function)" \
1452
- " set -l _entrypoint_before (builtin functions --all --names)" \
1453
- " set -l _entrypoint_critical_names contains test string source path functions set printf echo math count eval cd pwd" \
1454
- " set -l _entrypoint_snapshot_names" \
1455
- " set -l _entrypoint_snapshot_definitions" \
1456
- " set -l _entrypoint_snapshot_sources" \
1457
- " for _entrypoint_function in \$_entrypoint_before" \
1458
- " if test \"\$_entrypoint_function\" = \"\$_entrypoint_transaction_name\"; or not builtin functions -q \"\$_entrypoint_function\"" \
1459
- " continue" \
1460
- " end" \
1461
- " set -l _entrypoint_source (builtin functions --details \"\$_entrypoint_function\")" \
1462
- " if not builtin contains -- \"\$_entrypoint_function\" \$_entrypoint_critical_names; and builtin string match -q -r '^(embedded:|autoloaded:|builtin)' -- \"\$_entrypoint_source\"" \
1463
- " continue" \
1464
- " end" \
1465
- " set -a _entrypoint_snapshot_names \"\$_entrypoint_function\"" \
1466
- " set -a _entrypoint_snapshot_definitions (builtin functions \"\$_entrypoint_function\" | string collect)" \
1467
- " set -a _entrypoint_snapshot_sources \"\$_entrypoint_source\"" \
1468
- " end" \
1469
- " set -l _entrypoint_source_helper __valise_fish_entrypoint_source_(builtin random)" \
1470
- " function \$_entrypoint_source_helper" \
1471
- " builtin source \"\$argv[1]\"" \
1472
- " return \$status" \
1473
- " end" \
1474
- " \$_entrypoint_source_helper \"\$_entrypoint_file\"" \
1475
- " set -l _entrypoint_status \$status" \
1476
- " builtin functions -e \$_entrypoint_source_helper 2>/dev/null" \
1477
- " set -l _entrypoint_after (builtin functions --all --names)" \
1478
- " set -l _entrypoint_created" \
1479
- " for _entrypoint_function in \$_entrypoint_after" \
1480
- " if not builtin contains -- \"\$_entrypoint_function\" \$_entrypoint_before" \
1481
- " set -a _entrypoint_created \"\$_entrypoint_function\"" \
1482
- " end" \
1483
- " end" \
1484
- " set -l _entrypoint_replaced" \
1485
- " set -l _entrypoint_snapshot_index 1" \
1486
- " for _entrypoint_original in \$_entrypoint_snapshot_names" \
1487
- " set -l _entrypoint_saved \"\$_entrypoint_snapshot_definitions[\$_entrypoint_snapshot_index]\"" \
1488
- " set -l _entrypoint_live (builtin functions \"\$_entrypoint_original\" | string collect)" \
1489
- " if not builtin functions -q \"\$_entrypoint_original\"; or not test \"\$_entrypoint_live\" = \"\$_entrypoint_saved\"" \
1490
- " set -a _entrypoint_replaced \"\$_entrypoint_original\"" \
1491
- " end" \
1492
- " set _entrypoint_snapshot_index (builtin math \$_entrypoint_snapshot_index + 1)" \
1493
- " end" \
1494
- " set -l _entrypoint_embedded_replaced" \
1495
- " set _entrypoint_snapshot_index 1" \
1496
- " for _entrypoint_original in \$_entrypoint_snapshot_names" \
1497
- " if builtin contains -- \"\$_entrypoint_original\" \$_entrypoint_replaced; and builtin string match -q 'embedded:*' -- \"\$_entrypoint_snapshot_sources[\$_entrypoint_snapshot_index]\"" \
1498
- " set _entrypoint_embedded_replaced \"\$_entrypoint_original\"" \
1499
- " break" \
1500
- " end" \
1501
- " set _entrypoint_snapshot_index (builtin math \$_entrypoint_snapshot_index + 1)" \
1502
- " end" \
1503
- " if test -n \"\$_entrypoint_embedded_replaced\"" \
1504
- " builtin printf 'valise Fish integration: embedded Fish function was mutated: %s\\n' \"\$_entrypoint_embedded_replaced\" >&2" \
1505
- " test \$_entrypoint_status -ne 0; or set _entrypoint_status 125" \
1506
- " end" \
1507
- " if not test \"\$_entrypoint_expected_root\" = \"\$SHELL_PROJECT_ROOT\"" \
1508
- " test \$_entrypoint_status -ne 0; or set _entrypoint_status 1" \
1509
- " end" \
1510
- " if not builtin set -q VALISE_FISH_READY; or not test (builtin count \$VALISE_FISH_READY) -eq 1; or not string match -qr '^1\$' -- \"\$VALISE_FISH_READY\"" \
1511
- " test \$_entrypoint_status -ne 0; or set _entrypoint_status 1" \
1512
- " end" \
1513
- " if test \$_entrypoint_source_tree_mode = 1" \
1514
- " set -l _entrypoint_protected_names _sp_fish_loader_expected_source _sp_fish_metadata_expected_source _sp_fish_loader_bootstrap_mode _sp_fish_loader_bootstrap_seeds _sp_fish_loader_bootstrap_status _sp_fish_loaded_modules _sp_fish_module_roots _sp_fish_metadata_provider _sp_fish_loader_owned_exports _sp_fish_loader_owned_sources _sp_fish_legacy_owned_exports _sp_fish_legacy_owned_sources _sp_fish_metadata_owned_exports _sp_fish_metadata_owned_sources _sp_fish_entrypoint_owned_exports _sp_fish_entrypoint_owned_sources" \
1515
- " set -l _entrypoint_protected_changed 0" \
1516
- " for _entrypoint_protected_name in \$_entrypoint_protected_names" \
1517
- " if builtin set -q -g \"\$_entrypoint_protected_name\"; or builtin set -q -U \"\$_entrypoint_protected_name\"" \
1518
- " set _entrypoint_protected_changed 1" \
1519
- " if builtin set -q -g \"\$_entrypoint_protected_name\"; and not builtin set -e -g \"\$_entrypoint_protected_name\"; builtin exit 125; end" \
1520
- " if builtin set -q -U \"\$_entrypoint_protected_name\"; and not builtin set -e -U \"\$_entrypoint_protected_name\"; builtin exit 125; end" \
1521
- " end" \
1522
- " end" \
1523
- " if test \$_entrypoint_protected_changed -ne 0; and test \$_entrypoint_status -eq 0" \
1524
- " set _entrypoint_status 1" \
1525
- " end" \
1526
- " end" \
1527
- " # The entrypoint is selected only after verify-active authenticates its" \
1528
- " # immutable release. Its native metadata/loader state is therefore an" \
1529
- " # intentional result of authenticated activation, not caller mutation." \
1530
- " # Keep the exact caller-function and embedded-function checks above; those" \
1531
- " # are the custody boundary for this source transaction." \
1532
- " if test \$_entrypoint_status -ne 0; or test (builtin count \$_entrypoint_replaced) -ne 0" \
1533
- " for _entrypoint_function in \$_entrypoint_created" \
1534
- " if builtin functions -q \"\$_entrypoint_function\"" \
1535
- " builtin functions -e \"\$_entrypoint_function\"; or builtin exit 125" \
1536
- " end" \
1537
- " end" \
1538
- " if test (builtin count \$_entrypoint_replaced) -ne 0" \
1539
- " builtin printf '%s\\n' 'valise Fish integration: exact caller-function restoration is unavailable' >&2" \
1540
- " builtin exit 125" \
1541
- " end" \
1542
- " if builtin set -q -g VALISE_FISH_READY; and not builtin set -e -g VALISE_FISH_READY; builtin exit 125; end" \
1543
- " if builtin set -q -U VALISE_FISH_READY; and not builtin set -e -U VALISE_FISH_READY; builtin exit 125; end" \
1544
- " if test (builtin count \$_entrypoint_replaced) -ne 0; and test \$_entrypoint_status -eq 0" \
1545
- " set _entrypoint_status 1" \
1546
- " end" \
1547
- " return \$_entrypoint_status" \
1548
- " end" \
1549
- " # Publish only functions created by this authenticated entrypoint. The" \
1550
- " # source string is read back from Fish after sourcing; callers cannot" \
1551
- " # claim ownership by forging names or a parallel source ledger." \
1552
- " set -l _entrypoint_owned_sources" \
1553
- " for _entrypoint_function in \$_entrypoint_created" \
1554
- " if not builtin functions -q \"\$_entrypoint_function\"" \
1555
- " builtin printf '%s\\n' 'valise Fish integration: created entrypoint function disappeared before ownership publication' >&2" \
1556
- " builtin exit 125" \
1557
- " end" \
1558
- " set -l _entrypoint_source (builtin functions --details \"\$_entrypoint_function\")" \
1559
- " if test -z \"\$_entrypoint_source\"" \
1560
- " builtin printf '%s\\n' 'valise Fish integration: created entrypoint function has no authenticated source' >&2" \
1561
- " builtin exit 125" \
1562
- " end" \
1563
- " set -a _entrypoint_owned_sources \"\$_entrypoint_source\"" \
1564
- " end" \
1565
- " builtin set -g _sp_fish_entrypoint_owned_exports \$_entrypoint_created; or builtin exit 125" \
1566
- " builtin set -g _sp_fish_entrypoint_owned_sources \$_entrypoint_owned_sources; or builtin exit 125" \
1567
- " return 0" \
1568
- " end" \
1569
- " builtin set -gx SHELL_PROJECT_ROOT \"\$_valise_fish_active_root\"" \
1570
- " \$_valise_fish_entrypoint_runner \"\$_valise_fish_active_root/entrypoints/fish/profile.fish\" \"\$_valise_fish_active_root\" \"\$_valise_fish_source_tree_mode\"" \
1571
- " set -l _valise_fish_entrypoint_status \$status" \
1572
- " builtin functions -e \$_valise_fish_entrypoint_runner 2>/dev/null" \
1573
- " # The legacy runner is created before route selection; remove it on" \
1574
- " # every project-entrypoint return so it cannot leak into the caller." \
1575
- " builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
1576
- " if test \$_valise_fish_entrypoint_status -ne 0" \
1577
- " if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
1578
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
1579
- " builtin exit 125" \
1580
- " end" \
1581
- " \$_valise_fish_owned_cleanup" \
1582
- " if not builtin functions -q \$_valise_fish_root_restore_helper; or not builtin test (builtin functions \$_valise_fish_root_restore_helper | string collect) = \"\$_valise_fish_root_helper_definition\"" \
1583
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
1584
- " builtin exit 125" \
1585
- " end" \
1586
- " \$_valise_fish_root_restore_helper; or builtin exit 125" \
1587
- " return \$_valise_fish_entrypoint_status" \
1588
- " end" \
1589
- " if not builtin functions -q \$_valise_fish_success_cleanup_helper; or not builtin test (builtin functions \$_valise_fish_success_cleanup_helper | string collect) = \"\$_valise_fish_success_cleanup_helper_definition\"" \
1590
- " builtin printf '%s\\n' 'trusted success cleanup helper was modified' >&2" \
1591
- " builtin exit 125" \
1592
- " end" \
1593
- " \$_valise_fish_publish_active_helper; or builtin exit 125" \
1594
- " \$_valise_fish_success_cleanup_helper; or builtin exit 125" \
1595
- " return \$_valise_fish_entrypoint_status" \
1596
- "else" \
1597
- " if test -f \"\$_valise_fish_active_root/vendor/shell-profile/lib/fish/metadata.fish\"; and test -f \"\$_valise_fish_active_root/vendor/shell-profile/lib/fish/loader.fish\"" \
1598
- " builtin set -gx SHELL_PROJECT_ROOT \"\$_valise_fish_active_root\"" \
1599
- " builtin set -g _sp_fish_loader_expected_source \"\$_valise_fish_active_root/vendor/shell-profile/lib/fish/loader.fish\"" \
1600
- " builtin set -g _sp_fish_metadata_expected_source \"\$_valise_fish_active_root/vendor/shell-profile/lib/fish/metadata.fish\"" \
1601
- " # Metadata is executable Fish source; load it transactionally before the" \
1602
- " # native loader sees its declarations. The runner serializes caller functions" \
1603
- " # into caller-local Fish variables and sources metadata in an isolated helper scope." \
1604
- " set -l _valise_fish_metadata_transaction __valise_fish_metadata_transaction_(builtin random)" \
1605
- " function \$_valise_fish_metadata_transaction" \
1606
- " set -l _metadata_runner_name (builtin status function)" \
1607
- " set -l _metadata_persistence_helper \$argv[2]" \
1608
- " set -l _metadata_persistence_definition \$argv[3]" \
1609
- " set -l _metadata_persistence_durable_file \$argv[4]" \
1610
- " set -l _metadata_persistence_tmp_parent \$argv[5]" \
1611
- " set -l _metadata_expected_source ''" \
1612
- " if builtin set -q _sp_fish_metadata_expected_source" \
1613
- " set _metadata_expected_source \$_sp_fish_metadata_expected_source" \
1614
- " end" \
1615
- " if test -z \"\$_metadata_expected_source\"; or not builtin test \"\$argv[1]\" = \"\$_metadata_expected_source\"" \
1616
- " builtin printf '%s\\n' 'metadata source is not the authenticated expected source' >&2" \
1617
- " builtin exit 125" \
1618
- " end" \
1619
- " set -l _metadata_before (builtin functions --all --names)" \
1620
- " set -l _metadata_snapshot_names" \
1621
- " set -l _metadata_snapshot_definitions" \
1622
- " set -l _metadata_snapshot_sources" \
1623
- " set -l _metadata_snapshot_copy_sources" \
1624
- " set -l _metadata_snapshot_copies" \
1625
- " set -l _metadata_snapshot_nonce (builtin random)" \
1626
- " set -l _metadata_critical_names contains test string source path functions set printf echo math count eval cd pwd" \
1627
- " set -l _metadata_snapshot_status 0" \
1628
- " set -l _metadata_snapshot_index 1" \
1629
- " for _metadata_function in \$_metadata_before" \
1630
- " if test \"\$_metadata_function\" = \"\$_metadata_runner_name\"; or not builtin functions -q \"\$_metadata_function\"" \
1631
- " continue" \
1632
- " end" \
1633
- " set -l _metadata_source (builtin functions --details \"\$_metadata_function\")" \
1634
- " if builtin string match -q -r '^(autoloaded:|embedded:|builtin)' -- \"\$_metadata_source\"" \
1635
- " continue" \
1636
- " end" \
1637
- " set -l _metadata_definition (builtin functions \"\$_metadata_function\" | string collect)" \
1638
- " if test (builtin count \$_metadata_definition) -ne 1" \
1639
- " set _metadata_snapshot_status 125" \
1640
- " break" \
1641
- " end" \
1642
- " set -a _metadata_snapshot_names \"\$_metadata_function\"" \
1643
- " set -a _metadata_snapshot_definitions \"\$_metadata_definition\"" \
1644
- " set -l _metadata_snapshot_copy \"__valise_fish_metadata_snapshot_\"\$_metadata_snapshot_nonce\"_\"\$_metadata_snapshot_index" \
1645
- " if builtin functions -q \"\$_metadata_snapshot_copy\"; or not builtin functions --copy \"\$_metadata_function\" \"\$_metadata_snapshot_copy\"" \
1646
- " set _metadata_snapshot_status 125" \
1647
- " break" \
1648
- " end" \
1649
- " set -a _metadata_snapshot_sources \"\$_metadata_source\"" \
1650
- " set -a _metadata_snapshot_copy_sources (builtin functions --details \"\$_metadata_snapshot_copy\")" \
1651
- " set -a _metadata_snapshot_copies \"\$_metadata_snapshot_copy\"" \
1652
- " set _metadata_snapshot_index (builtin math \$_metadata_snapshot_index + 1)" \
1653
- " end" \
1654
- " # Preserve embedded critical definitions without copying them from inside this helper: Fish changes their provenance when copied here." \
1655
- " set -l _metadata_embedded_names" \
1656
- " set -l _metadata_embedded_sources" \
1657
- " set -l _metadata_critical_index 1" \
1658
- " for _metadata_critical_name in \$_metadata_critical_names" \
1659
- " if builtin functions -q \"\$_metadata_critical_name\"; and builtin string match -q 'embedded:*' -- (builtin functions --details \"\$_metadata_critical_name\")" \
1660
- " set -a _metadata_embedded_names \"\$_metadata_critical_name\"" \
1661
- " set -a _metadata_embedded_sources (builtin functions --details \"\$_metadata_critical_name\")" \
1662
- " end" \
1663
- " set _metadata_critical_index (builtin math \$_metadata_critical_index + 1)" \
1664
- " end" \
1665
- " # Metadata is executable Fish source. Keep the handshake, root, and" \
1666
- " # loader-private state transactional as well as its function namespace." \
1667
- " set -l _metadata_protected_names SHELL_PROJECT_ROOT VALISE_FISH_READY _sp_fish_loader_expected_source _sp_fish_metadata_expected_source _sp_fish_loader_bootstrap_mode _sp_fish_loader_bootstrap_seeds _sp_fish_loader_bootstrap_status _sp_fish_loaded_modules _sp_fish_module_roots _sp_fish_metadata_provider _sp_fish_loader_owned_exports _sp_fish_loader_owned_sources _sp_fish_legacy_owned_exports _sp_fish_legacy_owned_sources _sp_fish_metadata_owned_exports _sp_fish_metadata_owned_sources _sp_fish_entrypoint_owned_exports _sp_fish_entrypoint_owned_sources XDG_CONFIG_HOME TMPDIR HOME" \
1668
- " set -l _metadata_protected_prefix __valise_fish_metadata_state_(builtin random)" \
1669
- " set -l _metadata_capture_helper __valise_fish_metadata_capture_(builtin random)" \
1670
- " # Predeclare every capture slot in this transaction's local scope. The" \
1671
- " # The trusted capture helper writes into this transaction's local slots; metadata source" \
1672
- " # cannot enumerate or forge them as global rollback state." \
1673
- " for _metadata_slot_name in \$_metadata_protected_names" \
1674
- " for _metadata_slot_suffix in global_present global_exported global_values universal_present universal_exported universal_values" \
1675
- " set -f \"\$_metadata_protected_prefix\"_before_\"\$_metadata_slot_name\"_\"\$_metadata_slot_suffix\"" \
1676
- " set -f \"\$_metadata_protected_prefix\"_after_\"\$_metadata_slot_name\"_\"\$_metadata_slot_suffix\"" \
1677
- " end" \
1678
- " end" \
1679
- " function \$_metadata_capture_helper --no-scope-shadowing" \
1680
- " set -l _scope_name \$argv[1]" \
1681
- " set -l _scope_prefix \$argv[2]_\$_scope_name" \
1682
- " set -l _global_present 0" \
1683
- " builtin set -q -g \"\$_scope_name\"; and set _global_present 1" \
1684
- " set -l _global_exported 0" \
1685
- " builtin set -q -gx \"\$_scope_name\"; and set _global_exported 1" \
1686
- " set -l _global_values" \
1687
- " if test \$_global_present -eq 1" \
1688
- " set _global_values \$\$_scope_name" \
1689
- " end" \
1690
- " set -l _universal_present 0" \
1691
- " builtin set -q -U \"\$_scope_name\"; and set _universal_present 1" \
1692
- " set -l _universal_exported 0" \
1693
- " builtin set -q -Ux \"\$_scope_name\"; and set _universal_exported 1" \
1694
- " set -l _universal_values" \
1695
- " if test \$_universal_present -eq 1" \
1696
- " if test \$_global_present -eq 1" \
1697
- " builtin set -e -g \"\$_scope_name\"" \
1698
- " set _universal_values \$\$_scope_name" \
1699
- " set -l _restore_global_flags -g" \
1700
- " if test \$_global_exported -eq 1" \
1701
- " set _restore_global_flags -gx" \
1702
- " end" \
1703
- " builtin set \$_restore_global_flags \"\$_scope_name\" \$_global_values" \
1704
- " if test \$status -ne 0" \
1705
- " builtin exit 125" \
1706
- " end" \
1707
- " else" \
1708
- " set _universal_values \$\$_scope_name" \
1709
- " end" \
1710
- " end" \
1711
- " set \"\$_scope_prefix\"_global_present \$_global_present" \
1712
- " set \"\$_scope_prefix\"_global_exported \$_global_exported" \
1713
- " set \"\$_scope_prefix\"_global_values \$_global_values" \
1714
- " set \"\$_scope_prefix\"_universal_present \$_universal_present" \
1715
- " set \"\$_scope_prefix\"_universal_exported \$_universal_exported" \
1716
- " set \"\$_scope_prefix\"_universal_values \$_universal_values" \
1717
- " end" \
1718
- " set -l _metadata_restore_helper __valise_fish_metadata_restore_(builtin random)" \
1719
- " function \$_metadata_restore_helper --no-scope-shadowing" \
1720
- " set -l _restore_name \$argv[1]" \
1721
- " set -l _restore_prefix \$argv[2]_\$argv[1]" \
1722
- " set -l _expected_persistence_helper \$argv[3]" \
1723
- " set -l _expected_persistence_definition \$argv[4]" \
1724
- " set -l _global_present_var \"\$_restore_prefix\"_global_present" \
1725
- " set -l _global_exported_var \"\$_restore_prefix\"_global_exported" \
1726
- " set -l _global_values_var \"\$_restore_prefix\"_global_values" \
1727
- " set -l _universal_present_var \"\$_restore_prefix\"_universal_present" \
1728
- " set -l _universal_exported_var \"\$_restore_prefix\"_universal_exported" \
1729
- " set -l _universal_values_var \"\$_restore_prefix\"_universal_values" \
1730
- " set -l _expected_global_present \$\$_global_present_var" \
1731
- " set -l _expected_global_exported \$\$_global_exported_var" \
1732
- " set -l _expected_global_values \$\$_global_values_var" \
1733
- " set -l _expected_universal_present \$\$_universal_present_var" \
1734
- " set -l _expected_universal_exported \$\$_universal_exported_var" \
1735
- " set -l _expected_universal_values \$\$_universal_values_var" \
1736
- "" \
1737
- " # Every persistent erase/set is conditional or checked. An absent scope" \
1738
- " # is an expected before-image, not a failed erase operation." \
1739
- " if not builtin functions -q \$_expected_persistence_helper; or not builtin test (builtin functions \$_expected_persistence_helper | string collect) = \"\$_expected_persistence_definition\"" \
1740
- " builtin printf '%s\\n' 'trusted universal persistence verifier was modified' >&2" \
1741
- " return 125" \
1742
- " end" \
1743
- " if builtin set -q -g \"\$_restore_name\"" \
1744
- " builtin set -e -g \"\$_restore_name\"; or return 125" \
1745
- " end" \
1746
- " if builtin set -q -U \"\$_restore_name\"" \
1747
- " builtin set -e -U \"\$_restore_name\"; or return 125" \
1748
- " end" \
1749
- " # Restore universal before recreating a global shadow so Fish can read the" \
1750
- " # universal before-image without a false mutation failure." \
1751
- " if test \"\$_expected_universal_present\" = 1" \
1752
- " set -l _restore_universal_flags -U" \
1753
- " if test \"\$_expected_universal_exported\" = 1" \
1754
- " set _restore_universal_flags -Ux" \
1755
- " end" \
1756
- " builtin set \$_restore_universal_flags \"\$_restore_name\" \$_expected_universal_values" \
1757
- " if test \$status -ne 0" \
1758
- " return 125" \
1759
- " end" \
1760
- " end" \
1761
- " \$_expected_persistence_helper \"\$_metadata_persistence_durable_file\" \"\$_metadata_persistence_tmp_parent\" \"\$_restore_name\" \"\$_expected_universal_present\" \"\$_expected_universal_exported\" \$_expected_universal_values; or return 125" \
1762
- " if test \"\$_expected_global_present\" = 1" \
1763
- " set -l _restore_global_flags -g" \
1764
- " if test \"\$_expected_global_exported\" = 1" \
1765
- " set _restore_global_flags -gx" \
1766
- " end" \
1767
- " builtin set \$_restore_global_flags \"\$_restore_name\" \$_expected_global_values" \
1768
- " if test \$status -ne 0" \
1769
- " return 125" \
1770
- " end" \
1771
- " end" \
1772
- " # Verify global presence/export/value exactly before inspecting the" \
1773
- " # universal binding hidden by a global binding." \
1774
- " set -l _actual_global_present 0" \
1775
- " builtin set -q -g \"\$_restore_name\"; and set _actual_global_present 1" \
1776
- " set -l _actual_global_exported 0" \
1777
- " builtin set -q -gx \"\$_restore_name\"; and set _actual_global_exported 1" \
1778
- " set -l _actual_global_values" \
1779
- " if test \"\$_actual_global_present\" = 1" \
1780
- " set _actual_global_values \$\$_restore_name" \
1781
- " end" \
1782
- " if test \"\$_actual_global_present\" != \"\$_expected_global_present\"; or test \"\$_actual_global_exported\" != \"\$_expected_global_exported\"; or test (builtin count \$_actual_global_values) -ne (builtin count \$_expected_global_values)" \
1783
- " return 125" \
1784
- " end" \
1785
- " set -l _value_index 1" \
1786
- " while test \$_value_index -le (builtin count \$_expected_global_values)" \
1787
- " if not builtin test \"\$_expected_global_values[\$_value_index]\" = \"\$_actual_global_values[\$_value_index]\"" \
1788
- " return 125" \
1789
- " end" \
1790
- " builtin set _value_index (builtin math \$_value_index + 1)" \
1791
- " end" \
1792
- "" \
1793
- " set -l _hid_global 0" \
1794
- " if builtin set -q -g \"\$_restore_name\"" \
1795
- " builtin set -e -g \"\$_restore_name\"; or return 125" \
1796
- " set _hid_global 1" \
1797
- " end" \
1798
- " set -l _actual_universal_present 0" \
1799
- " builtin set -q -U \"\$_restore_name\"; and set _actual_universal_present 1" \
1800
- " set -l _actual_universal_exported 0" \
1801
- " builtin set -q -Ux \"\$_restore_name\"; and set _actual_universal_exported 1" \
1802
- " set -l _actual_universal_values" \
1803
- " if test \"\$_actual_universal_present\" = 1" \
1804
- " set _actual_universal_values \$\$_restore_name" \
1805
- " end" \
1806
- " if test \"\$_actual_universal_present\" != \"\$_expected_universal_present\"; or test \"\$_actual_universal_exported\" != \"\$_expected_universal_exported\"; or test (builtin count \$_actual_universal_values) -ne (builtin count \$_expected_universal_values)" \
1807
- " if test \$_hid_global -eq 1" \
1808
- " set -l _restore_global_flags -g" \
1809
- " if test \"\$_expected_global_exported\" = 1" \
1810
- " set _restore_global_flags -gx" \
1811
- " end" \
1812
- " builtin set \$_restore_global_flags \"\$_restore_name\" \$_expected_global_values" \
1813
- " if test \$status -ne 0" \
1814
- " return 125" \
1815
- " end" \
1816
- " end" \
1817
- " return 125" \
1818
- " end" \
1819
- " set _value_index 1" \
1820
- " while test \$_value_index -le (builtin count \$_expected_universal_values)" \
1821
- " if not builtin test \"\$_expected_universal_values[\$_value_index]\" = \"\$_actual_universal_values[\$_value_index]\"" \
1822
- " if test \$_hid_global -eq 1" \
1823
- " set -l _restore_global_flags -g" \
1824
- " if test \"\$_expected_global_exported\" = 1" \
1825
- " set _restore_global_flags -gx" \
1826
- " end" \
1827
- " builtin set \$_restore_global_flags \"\$_restore_name\" \$_expected_global_values" \
1828
- " if test \$status -ne 0" \
1829
- " return 125" \
1830
- " end" \
1831
- " end" \
1832
- " return 125" \
1833
- " end" \
1834
- " builtin set _value_index (builtin math \$_value_index + 1)" \
1835
- " end" \
1836
- " if test \$_hid_global -eq 1" \
1837
- " set -l _restore_global_flags -g" \
1838
- " if test \"\$_expected_global_exported\" = 1" \
1839
- " set _restore_global_flags -gx" \
1840
- " end" \
1841
- " builtin set \$_restore_global_flags \"\$_restore_name\" \$_expected_global_values" \
1842
- " if test \$status -ne 0" \
1843
- " return 125" \
1844
- " end" \
1845
- " end" \
1846
- "" \
1847
- " # The global binding was restored after universal inspection. Verify it" \
1848
- " # once more so the completed rollback has an exact before-image." \
1849
- " set _actual_global_present 0" \
1850
- " builtin set -q -g \"\$_restore_name\"; and set _actual_global_present 1" \
1851
- " set _actual_global_exported 0" \
1852
- " builtin set -q -gx \"\$_restore_name\"; and set _actual_global_exported 1" \
1853
- " set _actual_global_values" \
1854
- " if test \"\$_actual_global_present\" = 1" \
1855
- " set _actual_global_values \$\$_restore_name" \
1856
- " end" \
1857
- " if test \"\$_actual_global_present\" != \"\$_expected_global_present\"; or test \"\$_actual_global_exported\" != \"\$_expected_global_exported\"; or test (builtin count \$_actual_global_values) -ne (builtin count \$_expected_global_values)" \
1858
- " return 125" \
1859
- " end" \
1860
- " set _value_index 1" \
1861
- " while test \$_value_index -le (builtin count \$_expected_global_values)" \
1862
- " if not builtin test \"\$_expected_global_values[\$_value_index]\" = \"\$_actual_global_values[\$_value_index]\"" \
1863
- " return 125" \
1864
- " end" \
1865
- " builtin set _value_index (builtin math \$_value_index + 1)" \
1866
- " end" \
1867
- " return 0" \
1868
- " end" \
1869
- " set -l _metadata_capture_definition (builtin functions \"\$_metadata_capture_helper\" | string collect)" \
1870
- " set -l _metadata_restore_definition (builtin functions \"\$_metadata_restore_helper\" | string collect)" \
1871
- " if test (builtin count \$_metadata_capture_definition) -ne 1; or test (builtin count \$_metadata_restore_definition) -ne 1" \
1872
- " set _metadata_snapshot_status 125" \
1873
- " end" \
1874
- " if test \$_metadata_snapshot_status -eq 0" \
1875
- " for _metadata_protected_name in \$_metadata_protected_names" \
1876
- " \$_metadata_capture_helper \"\$_metadata_protected_name\" \"\$_metadata_protected_prefix\"_before" \
1877
- " end" \
1878
- " end" \
1879
- " set -l _metadata_source_helper __valise_fish_metadata_source_(builtin random)" \
1880
- " set -l _metadata_status 0" \
1881
- " if test \$_metadata_snapshot_status -eq 0" \
1882
- " function \$_metadata_source_helper" \
1883
- " builtin source \"\$argv[1]\"" \
1884
- " return \$status" \
1885
- " end" \
1886
- " \$_metadata_source_helper \"\$argv[1]\"" \
1887
- " set _metadata_status \$status" \
1888
- " builtin functions -e \$_metadata_source_helper 2>/dev/null" \
1889
- " else" \
1890
- " set -l _metadata_status \$_metadata_snapshot_status" \
1891
- " end" \
1892
- " set -l _metadata_protected_changed 0" \
1893
- " if test \$_metadata_snapshot_status -eq 0" \
1894
- " if not builtin functions -q \$_metadata_capture_helper; or not builtin test (builtin functions \$_metadata_capture_helper | string collect) = \"\$_metadata_capture_definition\"" \
1895
- " builtin printf '%s\\n' 'metadata capture helper was modified' >&2" \
1896
- " builtin exit 125" \
1897
- " end" \
1898
- " if not builtin functions -q \$_metadata_restore_helper; or not builtin test (builtin functions \$_metadata_restore_helper | string collect) = \"\$_metadata_restore_definition\"" \
1899
- " builtin printf '%s\\n' 'metadata restore helper was modified' >&2" \
1900
- " builtin exit 125" \
1901
- " end" \
1902
- " for _metadata_protected_name in \$_metadata_protected_names" \
1903
- " \$_metadata_capture_helper \"\$_metadata_protected_name\" \"\$_metadata_protected_prefix\"_after" \
1904
- " end" \
1905
- " builtin functions -e \$_metadata_capture_helper 2>/dev/null" \
1906
- " for _metadata_protected_name in \$_metadata_protected_names" \
1907
- " set -l _metadata_before_prefix \"\$_metadata_protected_prefix\"_before_\$_metadata_protected_name" \
1908
- " set -l _metadata_after_prefix \"\$_metadata_protected_prefix\"_after_\$_metadata_protected_name" \
1909
- " for _metadata_scope in global universal" \
1910
- " set -l _metadata_before_present_var \"\$_metadata_before_prefix\"_\"\$_metadata_scope\"_present" \
1911
- " set -l _metadata_after_present_var \"\$_metadata_after_prefix\"_\"\$_metadata_scope\"_present" \
1912
- " set -l _metadata_before_exported_var \"\$_metadata_before_prefix\"_\"\$_metadata_scope\"_exported" \
1913
- " set -l _metadata_after_exported_var \"\$_metadata_after_prefix\"_\"\$_metadata_scope\"_exported" \
1914
- " set -l _metadata_before_values_var \"\$_metadata_before_prefix\"_\"\$_metadata_scope\"_values" \
1915
- " set -l _metadata_after_values_var \"\$_metadata_after_prefix\"_\"\$_metadata_scope\"_values" \
1916
- " if not test \$\$_metadata_before_present_var = \$\$_metadata_after_present_var; or not test \$\$_metadata_before_exported_var = \$\$_metadata_after_exported_var" \
1917
- " set _metadata_protected_changed 1" \
1918
- " else if test (builtin count \$\$_metadata_before_values_var) -ne (builtin count \$\$_metadata_after_values_var)" \
1919
- " set _metadata_protected_changed 1" \
1920
- " else" \
1921
- " set -l _metadata_value_index 1" \
1922
- " while test \$_metadata_value_index -le (builtin count \$\$_metadata_before_values_var)" \
1923
- " if not test \"\$\$_metadata_before_values_var[\$_metadata_value_index]\" = \"\$\$_metadata_after_values_var[\$_metadata_value_index]\"" \
1924
- " set _metadata_protected_changed 1" \
1925
- " break" \
1926
- " end" \
1927
- " set _metadata_value_index (builtin math \$_metadata_value_index + 1)" \
1928
- " end" \
1929
- " end" \
1930
- " end" \
1931
- " end" \
1932
- " end" \
1933
- " set -l _metadata_after (builtin functions --all --names)" \
1934
- " set -l _metadata_created" \
1935
- " for _metadata_function in \$_metadata_after" \
1936
- " if not builtin contains -- \"\$_metadata_function\" \$_metadata_before" \
1937
- " if not builtin contains -- \"\$_metadata_function\" \$_metadata_snapshot_copies" \
1938
- " set -a _metadata_created \"\$_metadata_function\"" \
1939
- " end" \
1940
- " end" \
1941
- " end" \
1942
- " set -l _metadata_critical_created" \
1943
- " for _metadata_function in \$_metadata_created" \
1944
- " if builtin contains -- \"\$_metadata_function\" \$_metadata_critical_names" \
1945
- " set -a _metadata_critical_created \"\$_metadata_function\"" \
1946
- " end" \
1947
- " end" \
1948
- " set -l _metadata_embedded_replaced" \
1949
- " set -l _metadata_embedded_index 1" \
1950
- " for _metadata_embedded_name in \$_metadata_embedded_names" \
1951
- " if not builtin functions -q \"\$_metadata_embedded_name\"; or not builtin test (builtin functions --details \"\$_metadata_embedded_name\") = \"\$_metadata_embedded_sources[\$_metadata_embedded_index]\"" \
1952
- " set -a _metadata_embedded_replaced \"\$_metadata_embedded_name\"" \
1953
- " end" \
1954
- " set _metadata_embedded_index (builtin math \$_metadata_embedded_index + 1)" \
1955
- " end" \
1956
- " if builtin functions -q cd" \
1957
- " set -l _metadata_cd_source (builtin functions --details cd)" \
1958
- " if not builtin contains -- \"\$_metadata_cd_source\" embedded:functions/cd.fish /usr/share/fish/functions/cd.fish /usr/local/share/fish/functions/cd.fish /opt/local/share/fish/functions/cd.fish /opt/homebrew/share/fish/functions/cd.fish" \
1959
- " set -a _metadata_embedded_replaced cd" \
1960
- " end" \
1961
- " end" \
1962
- " set -l _metadata_replaced" \
1963
- " set -l _metadata_untrusted_replaced" \
1964
- " set -l _metadata_snapshot_compromised 0" \
1965
- " # Snapshot aliases are visible Fish functions. Validate source identity and" \
1966
- " # the complete saved definition before trusting one for rollback." \
1967
- " if test \$_metadata_snapshot_status -eq 0" \
1968
- " set -l _metadata_snapshot_index 1" \
1969
- " for _metadata_function in \$_metadata_snapshot_names" \
1970
- " set -l _metadata_saved \"\$_metadata_snapshot_definitions[\$_metadata_snapshot_index]\"" \
1971
- " set -l _metadata_saved_lines (string split \\n -- \"\$_metadata_saved\")" \
1972
- " set -l _metadata_snapshot_copy \"\$_metadata_snapshot_copies[\$_metadata_snapshot_index]\"" \
1973
- " if not builtin functions -q \"\$_metadata_snapshot_copy\"" \
1974
- " set _metadata_snapshot_compromised 1" \
1975
- " break" \
1976
- " end" \
1977
- " set -l _metadata_copy_lines (string split \\n -- (builtin functions \"\$_metadata_snapshot_copy\" | string collect))" \
1978
- " if test (builtin functions --details \"\$_metadata_snapshot_copy\") != \"\$_metadata_snapshot_copy_sources[\$_metadata_snapshot_index]\"; or test (builtin count \$_metadata_copy_lines) -ne (builtin count \$_metadata_saved_lines)" \
1979
- " set _metadata_snapshot_compromised 1" \
1980
- " break" \
1981
- " end" \
1982
- " set -l _metadata_copy_origin (string replace -r ', copied .*' '' -- \"\$_metadata_copy_lines[1]\")" \
1983
- " set -l _metadata_saved_origin (string replace -r ', copied .*' '' -- \"\$_metadata_saved_lines[1]\")" \
1984
- " if not builtin test \"\$_metadata_copy_origin\" = \"\$_metadata_saved_origin\"" \
1985
- " set _metadata_snapshot_compromised 1" \
1986
- " break" \
1987
- " end" \
1988
- " set -l _metadata_copy_line 2" \
1989
- " while test \$_metadata_copy_line -le (builtin count \$_metadata_saved_lines)" \
1990
- " set -l _metadata_copy_expected \"\$_metadata_saved_lines[\$_metadata_copy_line]\"" \
1991
- " set -l _metadata_copy_actual \"\$_metadata_copy_lines[\$_metadata_copy_line]\"" \
1992
- " if test \$_metadata_copy_line -eq 2" \
1993
- " set _metadata_copy_expected (string replace -r '^function [^[:space:]]+' 'function __valise_snapshot__' -- \"\$_metadata_copy_expected\")" \
1994
- " set _metadata_copy_actual (string replace -r '^function [^[:space:]]+' 'function __valise_snapshot__' -- \"\$_metadata_copy_actual\")" \
1995
- " end" \
1996
- " if not builtin test \"\$_metadata_copy_actual\" = \"\$_metadata_copy_expected\"" \
1997
- " set _metadata_snapshot_compromised 1" \
1998
- " break" \
1999
- " end" \
2000
- " set _metadata_copy_line (builtin math \$_metadata_copy_line + 1)" \
2001
- " end" \
2002
- " test \$_metadata_snapshot_compromised -eq 0; or break" \
2003
- " set _metadata_snapshot_index (builtin math \$_metadata_snapshot_index + 1)" \
2004
- " end" \
2005
- " end" \
2006
- " if test \$_metadata_snapshot_compromised -ne 0" \
2007
- " builtin printf '%s\\n' 'valise Fish integration: metadata rollback custody was modified' >&2" \
2008
- " builtin exit 125" \
2009
- " end" \
2010
- " if test \$_metadata_snapshot_status -eq 0" \
2011
- " set -l _metadata_snapshot_index 1" \
2012
- " for _metadata_function in \$_metadata_snapshot_names" \
2013
- " set -l _metadata_saved \"\$_metadata_snapshot_definitions[\$_metadata_snapshot_index]\"" \
2014
- " set -l _metadata_saved_lines (string split \\n -- \"\$_metadata_saved\")" \
2015
- " set -l _metadata_live_lines" \
2016
- " set -l _metadata_changed 0" \
2017
- " if not builtin functions -q \"\$_metadata_function\"" \
2018
- " set _metadata_changed 1" \
2019
- " else" \
2020
- " set _metadata_live_lines (string split \\n -- (builtin functions \"\$_metadata_function\" | string collect))" \
2021
- " if test (builtin count \$_metadata_live_lines) -ne (builtin count \$_metadata_saved_lines)" \
2022
- " set _metadata_changed 1" \
2023
- " else" \
2024
- " set -l _metadata_line 1" \
2025
- " while test \$_metadata_line -le (builtin count \$_metadata_saved_lines)" \
2026
- " if not builtin test \"\$_metadata_saved_lines[\$_metadata_line]\" = \"\$_metadata_live_lines[\$_metadata_line]\"" \
2027
- " set _metadata_changed 1" \
2028
- " break" \
2029
- " end" \
2030
- " set _metadata_line (builtin math \$_metadata_line + 1)" \
2031
- " end" \
2032
- " end" \
2033
- " end" \
2034
- " if test \$_metadata_changed -eq 1" \
2035
- " set -a _metadata_replaced \"\$_metadata_function\"" \
2036
- " set -l _metadata_previous_owned 0" \
2037
- " set -l _metadata_previous_index 1" \
2038
- " for _metadata_previous_name in \$_sp_fish_metadata_owned_exports" \
2039
- " if test \"\$_metadata_previous_name\" = \"\$_metadata_function\"; and test \"\$_sp_fish_metadata_owned_sources[\$_metadata_previous_index]\" = \"\$_metadata_snapshot_sources[\$_metadata_snapshot_index]\"" \
2040
- " set _metadata_previous_owned 1" \
2041
- " break" \
2042
- " end" \
2043
- " set _metadata_previous_index (builtin math \$_metadata_previous_index + 1)" \
2044
- " end" \
2045
- " if test \$_metadata_previous_owned -eq 0" \
2046
- " set -a _metadata_untrusted_replaced \"\$_metadata_function\"" \
2047
- " end" \
2048
- " end" \
2049
- " set _metadata_snapshot_index (builtin math \$_metadata_snapshot_index + 1)" \
2050
- " end" \
2051
- " end" \
2052
- " # A metadata source can edit fish_variables directly without changing" \
2053
- " # any visible Fish binding. Verify every protected universal before" \
2054
- " # publishing success so that path is transactional too." \
2055
- " set -l _metadata_persistence_changed 0" \
2056
- " if test \$_metadata_snapshot_status -eq 0" \
2057
- " if not builtin functions -q \$_metadata_persistence_helper; or not builtin test (builtin functions \$_metadata_persistence_helper | string collect) = \"\$_metadata_persistence_definition\"" \
2058
- " builtin printf '%s\\n' 'metadata persistence verifier was modified' >&2" \
2059
- " builtin exit 125" \
2060
- " end" \
2061
- " for _metadata_protected_name in \$_metadata_protected_names" \
2062
- " set -l _metadata_after_prefix \"\$_metadata_protected_prefix\"_after_\$_metadata_protected_name" \
2063
- " set -l _metadata_after_present_var \"\$_metadata_after_prefix\"_universal_present" \
2064
- " set -l _metadata_after_exported_var \"\$_metadata_after_prefix\"_universal_exported" \
2065
- " set -l _metadata_after_values_var \"\$_metadata_after_prefix\"_universal_values" \
2066
- " \$_metadata_persistence_helper \"\$_metadata_persistence_durable_file\" \"\$_metadata_persistence_tmp_parent\" \"\$_metadata_protected_name\" \"\$\$_metadata_after_present_var\" \"\$\$_metadata_after_exported_var\" \$\$_metadata_after_values_var" \
2067
- " if test \$status -ne 0" \
2068
- " set _metadata_persistence_changed 1" \
2069
- " break" \
2070
- " end" \
2071
- " end" \
2072
- " end" \
2073
- " set -l _metadata_failure 0" \
2074
- " if test \$_metadata_snapshot_status -ne 0" \
2075
- " set _metadata_status \$_metadata_snapshot_status" \
2076
- " set _metadata_failure 1" \
2077
- " end" \
2078
- " if test \$_metadata_status -ne 0" \
2079
- " set _metadata_failure 1" \
2080
- " set _metadata_protected_changed 1" \
2081
- " end" \
2082
- " if test (builtin count \$_metadata_untrusted_replaced) -ne 0" \
2083
- " set _metadata_failure 1" \
2084
- " end" \
2085
- " if test (builtin count \$_metadata_embedded_replaced) -ne 0" \
2086
- " set _metadata_failure 1" \
2087
- " end" \
2088
- " if test \$_metadata_protected_changed -ne 0" \
2089
- " set _metadata_failure 1" \
2090
- " test \$_metadata_status -eq 0; and set _metadata_status 1" \
2091
- " end" \
2092
- " if test \$_metadata_persistence_changed -ne 0" \
2093
- " set _metadata_failure 1" \
2094
- " set _metadata_protected_changed 1" \
2095
- " set _metadata_status 125" \
2096
- " end" \
2097
- " if test \$_metadata_failure -ne 0" \
2098
- " if test \$_metadata_snapshot_status -ne 0" \
2099
- " builtin printf '%s\\n' 'valise Fish integration: metadata rollback snapshot unavailable' >&2" \
2100
- " builtin exit 125" \
2101
- " end" \
2102
- " if test (builtin count \$_metadata_untrusted_replaced) -ne 0" \
2103
- " builtin printf '%s\\n' 'valise Fish integration: metadata source replaced a caller-owned function' >&2" \
2104
- " builtin exit 125" \
2105
- " end" \
2106
- " if test (builtin count \$_metadata_embedded_replaced) -ne 0" \
2107
- " builtin printf '%s\\n' 'valise Fish integration: embedded Fish function was mutated' >&2" \
2108
- " builtin exit 125" \
2109
- " end" \
2110
- " if test (builtin count \$_metadata_replaced) -ne 0" \
2111
- " builtin printf '%s\\n' 'valise Fish integration: exact metadata function restoration is unavailable' >&2" \
2112
- " builtin exit 125" \
2113
- " end" \
2114
- " for _metadata_function in \$_metadata_created" \
2115
- " if not test \"\$_metadata_function\" = \"\$_metadata_restore_helper\"" \
2116
- " if builtin functions -q \"\$_metadata_function\"" \
2117
- " builtin functions -e \"\$_metadata_function\"; or builtin exit 125" \
2118
- " end" \
2119
- " end" \
2120
- " end" \
2121
- " set -l _metadata_restore_failed 0" \
2122
- " if test \$_metadata_protected_changed -ne 0" \
2123
- " for _metadata_protected_name in \$_metadata_protected_names" \
2124
- " \$_metadata_restore_helper \"\$_metadata_protected_name\" \"\$_metadata_protected_prefix\"_before \"\$_metadata_persistence_helper\" \"\$_metadata_persistence_definition\"" \
2125
- " if test \$status -ne 0" \
2126
- " set _metadata_restore_failed 1" \
2127
- " end" \
2128
- " end" \
2129
- " end" \
2130
- " builtin functions -e \$_metadata_restore_helper 2>/dev/null" \
2131
- " for _metadata_snapshot_copy in \$_metadata_snapshot_copies" \
2132
- " if builtin functions -q \"\$_metadata_snapshot_copy\"" \
2133
- " builtin functions -e \"\$_metadata_snapshot_copy\"; or builtin exit 125" \
2134
- " end" \
2135
- " end" \
2136
- " if test \$_metadata_restore_failed -ne 0" \
2137
- " set _metadata_status 125" \
2138
- " end" \
2139
- " return \$_metadata_status" \
2140
- " end" \
2141
- " for _metadata_snapshot_copy in \$_metadata_snapshot_copies" \
2142
- " builtin functions -q \"\$_metadata_snapshot_copy\"; and builtin functions -e \"\$_metadata_snapshot_copy\"" \
2143
- " end" \
2144
- " builtin functions -e \$_metadata_restore_helper 2>/dev/null" \
2145
- " builtin set -g _sp_fish_metadata_owned_exports" \
2146
- " builtin set -g _sp_fish_metadata_owned_sources" \
2147
- " for _metadata_function in \$_metadata_after" \
2148
- " set -l _metadata_source (builtin functions --details \"\$_metadata_function\")" \
2149
- " if test \"\$_metadata_source\" = \"\$_metadata_expected_source\"" \
2150
- " builtin set -a _sp_fish_metadata_owned_exports \"\$_metadata_function\"" \
2151
- " builtin set -a _sp_fish_metadata_owned_sources \"\$_metadata_source\"" \
2152
- " end" \
2153
- " end" \
2154
- " return \$_metadata_status" \
2155
- " end" \
2156
- " \$_valise_fish_metadata_transaction \"\$_valise_fish_active_root/vendor/shell-profile/lib/fish/metadata.fish\" \"\$_valise_fish_persistence_verify_helper\" \"\$_valise_fish_persistence_helper_definition\" \"\$_valise_fish_persistence_durable_file\" \"\$_valise_fish_persistence_tmp_parent\"" \
2157
- " set -l _valise_fish_metadata_status \$status" \
2158
- " builtin functions -e \$_valise_fish_metadata_transaction 2>/dev/null" \
2159
- " if test \$_valise_fish_metadata_status -ne 0" \
2160
- " builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
2161
- " if builtin set -q -g VALISE_FISH_READY; and not builtin set -e -g VALISE_FISH_READY; builtin exit 125; end" \
2162
- " if builtin set -q -U VALISE_FISH_READY; and not builtin set -e -U VALISE_FISH_READY; builtin exit 125; end" \
2163
- " if builtin set -q -g _sp_fish_loader_bootstrap_status; and not builtin set -e -g _sp_fish_loader_bootstrap_status; builtin exit 125; end" \
2164
- " if builtin set -q -U _sp_fish_loader_bootstrap_status; and not builtin set -e -U _sp_fish_loader_bootstrap_status; builtin exit 125; end" \
2165
- " if builtin set -q -g _sp_fish_loader_bootstrap_mode; and not builtin set -e -g _sp_fish_loader_bootstrap_mode; builtin exit 125; end" \
2166
- " if builtin set -q -U _sp_fish_loader_bootstrap_mode; and not builtin set -e -U _sp_fish_loader_bootstrap_mode; builtin exit 125; end" \
2167
- " if builtin set -q -g _sp_fish_loader_bootstrap_seeds; and not builtin set -e -g _sp_fish_loader_bootstrap_seeds; builtin exit 125; end" \
2168
- " if builtin set -q -U _sp_fish_loader_bootstrap_seeds; and not builtin set -e -U _sp_fish_loader_bootstrap_seeds; builtin exit 125; end" \
2169
- " if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
2170
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
2171
- " builtin exit 125" \
2172
- " end" \
2173
- " \$_valise_fish_owned_cleanup" \
2174
- " if not builtin functions -q \$_valise_fish_root_restore_helper; or not builtin test (builtin functions \$_valise_fish_root_restore_helper | string collect) = \"\$_valise_fish_root_helper_definition\"" \
2175
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
2176
- " builtin exit 125" \
2177
- " end" \
2178
- " \$_valise_fish_root_restore_helper; or builtin exit 125" \
2179
- " printf 'valise Fish integration: metadata loader failed with status %d\\n' \$_valise_fish_metadata_status >&2" \
2180
- " return \$_valise_fish_metadata_status" \
2181
- " else" \
2182
- " if builtin set -q -g _sp_fish_loader_bootstrap_status; and not builtin set -e -g _sp_fish_loader_bootstrap_status; builtin exit 125; end" \
2183
- " if builtin set -q -U _sp_fish_loader_bootstrap_status; and not builtin set -e -U _sp_fish_loader_bootstrap_status; builtin exit 125; end" \
2184
- " if builtin set -q -g _sp_fish_loader_bootstrap_mode; and not builtin set -e -g _sp_fish_loader_bootstrap_mode; builtin exit 125; end" \
2185
- " if builtin set -q -U _sp_fish_loader_bootstrap_mode; and not builtin set -e -U _sp_fish_loader_bootstrap_mode; builtin exit 125; end" \
2186
- " if builtin set -q -g _sp_fish_loader_bootstrap_seeds; and not builtin set -e -g _sp_fish_loader_bootstrap_seeds; builtin exit 125; end" \
2187
- " if builtin set -q -U _sp_fish_loader_bootstrap_seeds; and not builtin set -e -U _sp_fish_loader_bootstrap_seeds; builtin exit 125; end" \
2188
- " builtin set -g _sp_fish_loader_bootstrap_mode strict" \
2189
- " builtin set -g _sp_fish_loader_bootstrap_seeds fish_path fish_environment fish_secure_local_bin" \
2190
- " builtin source \"\$_valise_fish_active_root/vendor/shell-profile/lib/fish/loader.fish\"" \
2191
- " set -l _valise_fish_source_status \$status" \
2192
- " if builtin set -q -g VALISE_FISH_READY; and not builtin set -e -g VALISE_FISH_READY; builtin exit 125; end" \
2193
- " if builtin set -q -U VALISE_FISH_READY; and not builtin set -e -U VALISE_FISH_READY; builtin exit 125; end" \
2194
- " set -l _valise_fish_status_published 0" \
2195
- " set -l _valise_fish_loader_status 1" \
2196
- " if builtin set -q _sp_fish_loader_bootstrap_status" \
2197
- " set _valise_fish_status_published 1" \
2198
- " set _valise_fish_loader_status \$_sp_fish_loader_bootstrap_status" \
2199
- " end" \
2200
- " if builtin set -q -g _sp_fish_loader_bootstrap_mode; and not builtin set -e -g _sp_fish_loader_bootstrap_mode; builtin exit 125; end" \
2201
- " if builtin set -q -U _sp_fish_loader_bootstrap_mode; and not builtin set -e -U _sp_fish_loader_bootstrap_mode; builtin exit 125; end" \
2202
- " if builtin set -q -g _sp_fish_loader_bootstrap_seeds; and not builtin set -e -g _sp_fish_loader_bootstrap_seeds; builtin exit 125; end" \
2203
- " if builtin set -q -U _sp_fish_loader_bootstrap_seeds; and not builtin set -e -U _sp_fish_loader_bootstrap_seeds; builtin exit 125; end" \
2204
- " if builtin set -q -g _sp_fish_loader_bootstrap_status; and not builtin set -e -g _sp_fish_loader_bootstrap_status; builtin exit 125; end" \
2205
- " if builtin set -q -U _sp_fish_loader_bootstrap_status; and not builtin set -e -U _sp_fish_loader_bootstrap_status; builtin exit 125; end" \
2206
- " if test \$_valise_fish_source_status -ne 0" \
2207
- " builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
2208
- " if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
2209
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
2210
- " builtin exit 125" \
2211
- " end" \
2212
- " \$_valise_fish_owned_cleanup" \
2213
- " if not builtin functions -q \$_valise_fish_root_restore_helper; or not builtin test (builtin functions \$_valise_fish_root_restore_helper | string collect) = \"\$_valise_fish_root_helper_definition\"" \
2214
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
2215
- " builtin exit 125" \
2216
- " end" \
2217
- " \$_valise_fish_root_restore_helper; or builtin exit 125" \
2218
- " printf 'valise Fish integration: native loader source failed with status %d\\n' \$_valise_fish_source_status >&2" \
2219
- " return \$_valise_fish_source_status" \
2220
- " else" \
2221
- " if test \$_valise_fish_status_published -ne 1" \
2222
- " if builtin functions -q sp_fish_loader_load_ordered; and test -f \"\$_valise_fish_active_root/generated/installed-modules.fish\"" \
2223
- " # Legacy releases expose only the authenticated generated Fish plan." \
2224
- " \$_valise_fish_legacy_runner \"\$_valise_fish_active_root\" \"\$_valise_fish_active_root/generated/installed-modules.fish\"" \
2225
- " set -l _valise_fish_legacy_status \$status" \
2226
- " builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
2227
- " if test \$_valise_fish_legacy_status -ne 0" \
2228
- " if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
2229
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
2230
- " builtin exit 125" \
2231
- " end" \
2232
- " \$_valise_fish_owned_cleanup" \
2233
- " if not builtin functions -q \$_valise_fish_root_restore_helper; or not builtin test (builtin functions \$_valise_fish_root_restore_helper | string collect) = \"\$_valise_fish_root_helper_definition\"" \
2234
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
2235
- " builtin exit 125" \
2236
- " end" \
2237
- " \$_valise_fish_root_restore_helper; or builtin exit 125" \
2238
- " return \$_valise_fish_legacy_status" \
2239
- " end" \
2240
- " \$_valise_fish_publish_active_helper; or builtin exit 125" \
2241
- " else" \
2242
- " if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
2243
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
2244
- " builtin exit 125" \
2245
- " end" \
2246
- " \$_valise_fish_owned_cleanup" \
2247
- " builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
2248
- " if not builtin functions -q \$_valise_fish_root_restore_helper; or not builtin test (builtin functions \$_valise_fish_root_restore_helper | string collect) = \"\$_valise_fish_root_helper_definition\"" \
2249
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
2250
- " builtin exit 125" \
2251
- " end" \
2252
- " \$_valise_fish_root_restore_helper; or builtin exit 125" \
2253
- " printf '%s\\n' 'valise Fish integration: native loader did not publish a fresh status' >&2" \
2254
- " return 1" \
2255
- " end" \
2256
- " else" \
2257
- " if not string match -qr '^[0-9]+$' -- \"\$_valise_fish_loader_status\"; or test \$_valise_fish_loader_status -ne 0" \
2258
- " builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
2259
- " if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
2260
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
2261
- " builtin exit 125" \
2262
- " end" \
2263
- " \$_valise_fish_owned_cleanup" \
2264
- " if not builtin functions -q \$_valise_fish_root_restore_helper; or not builtin test (builtin functions \$_valise_fish_root_restore_helper | string collect) = \"\$_valise_fish_root_helper_definition\"" \
2265
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
2266
- " builtin exit 125" \
2267
- " end" \
2268
- " \$_valise_fish_root_restore_helper; or builtin exit 125" \
2269
- " printf 'valise Fish integration: native loader failed with status %s\\n' \$_valise_fish_loader_status >&2" \
2270
- " return \$_valise_fish_loader_status" \
2271
- " end" \
2272
- " end" \
2273
- " builtin set -gx VALISE_FISH_READY 1" \
2274
- " builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
2275
- " end" \
2276
- " end" \
2277
- "else" \
2278
- " if test -f \"\$_valise_fish_active_root/generated/installed-modules.fish\"" \
2279
- " # Compatibility path for releases that predate native Fish infrastructure." \
2280
- " \$_valise_fish_legacy_runner \"\$_valise_fish_active_root\" \"\$_valise_fish_active_root/generated/installed-modules.fish\"" \
2281
- " set -l _valise_fish_legacy_status \$status" \
2282
- " builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
2283
- " if test \$_valise_fish_legacy_status -ne 0" \
2284
- " if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
2285
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
2286
- " builtin exit 125" \
2287
- " end" \
2288
- " \$_valise_fish_owned_cleanup" \
2289
- " if not builtin functions -q \$_valise_fish_root_restore_helper; or not builtin test (builtin functions \$_valise_fish_root_restore_helper | string collect) = \"\$_valise_fish_root_helper_definition\"" \
2290
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
2291
- " builtin exit 125" \
2292
- " end" \
2293
- " \$_valise_fish_root_restore_helper; or builtin exit 125" \
2294
- " return \$_valise_fish_legacy_status" \
2295
- " end" \
2296
- " \$_valise_fish_publish_active_helper; or builtin exit 125" \
2297
- " else" \
2298
- " printf '%s\\n' 'valise Fish integration: native Fish loader infrastructure is unavailable' >&2" \
2299
- " builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
2300
- " if not builtin functions -q \$_valise_fish_owned_cleanup; or not builtin test (builtin functions \$_valise_fish_owned_cleanup | string collect) = \"\$_valise_fish_owned_cleanup_definition\"" \
2301
- " builtin printf '%s\\n' 'trusted ownership cleanup helper was modified' >&2" \
2302
- " builtin exit 125" \
2303
- " end" \
2304
- " \$_valise_fish_owned_cleanup" \
2305
- " if not builtin functions -q \$_valise_fish_root_restore_helper; or not builtin test (builtin functions \$_valise_fish_root_restore_helper | string collect) = \"\$_valise_fish_root_helper_definition\"" \
2306
- " builtin printf '%s\\n' 'trusted root restore helper was modified' >&2" \
2307
- " builtin exit 125" \
2308
- " end" \
2309
- " \$_valise_fish_root_restore_helper; or builtin exit 125" \
2310
- " return 1" \
2311
- "end" \
2312
- " end" \
2313
- "end" \
2314
- "builtin functions -e \$_valise_fish_legacy_runner 2>/dev/null" \
2315
- "if not builtin functions -q \$_valise_fish_success_cleanup_helper; or not builtin test (builtin functions \$_valise_fish_success_cleanup_helper | string collect) = \"\$_valise_fish_success_cleanup_helper_definition\"" \
2316
- " builtin printf '%s\\n' 'trusted success cleanup helper was modified' >&2" \
2317
- " builtin exit 125" \
2318
- "end" \
2319
- "\$_valise_fish_success_cleanup_helper; or builtin exit 125" \
2320
- "end"
2321
- }
2322
-
2323
- cmd_init() {
2324
- _shell="${1:-}"
2325
- if [ "$#" -gt 0 ]; then
2326
- shift
2327
- fi
2328
- _fish_source_tree_mode=0
2329
- for _arg do
2330
- case "$_arg" in
2331
- --source-tree) _fish_source_tree_mode=1 ;;
2332
- *) die "unknown init option: $_arg" ;;
2333
- esac
2334
- done
2335
- if [ -z "$_shell" ]; then
2336
- # Detect current shell
2337
- case "${SHELL:-}" in
2338
- *bash) _shell=bash ;;
2339
- *zsh) _shell=zsh ;;
2340
- *ksh) _shell=ksh ;;
2341
- *fish) _shell=fish ;;
2342
- *) _shell=sh ;;
2343
- esac
2344
- fi
2345
-
2346
- case "$_shell" in
2347
- bash|zsh|ksh|sh)
2348
- # shell_quote() returns a POSIX single-quoted literal (e.g.
2349
- # '/home/u/.config/valise/active'). Embed that literal directly
2350
- # into the generated snippet as the right-hand side of an
2351
- # assignment to _valise_active_link. Every later use references
2352
- # "$_valise_active_link" in double quotes — no visually-unquoted
2353
- # shell_quote output remains in the emitted text.
2354
- _shell_active_literal=$(shell_quote "$VALISE_ACTIVE_LINK") || return 1
2355
- printf '%s\n' \
2356
- "# valise shell integration" \
2357
- "_valise_active_link=${_shell_active_literal}" \
2358
- "if [ -L \"\$_valise_active_link/entrypoints/profile.sh\" ] || [ -f \"\$_valise_active_link/entrypoints/profile.sh\" ]; then" \
2359
- " _valise_active=\$(cd \"\$_valise_active_link\" 2>/dev/null && pwd -P)" \
2360
- " if [ -n \"\$_valise_active\" ]; then" \
2361
- " VALISE_ROOT=\"\$_valise_active\"" \
2362
- " . \"\$_valise_active/entrypoints/profile.sh\"" \
2363
- " fi" \
2364
- " unset _valise_active" \
2365
- "fi" \
2366
- "unset _valise_active_link"
2367
- ;;
2368
- fish)
2369
- print_fish_integration
2370
- ;;
30
+ case "$_valise_link" in
31
+ /*) _valise_self=$_valise_link ;;
2371
32
  *)
2372
- die "unsupported shell: $_shell (use bash, zsh, ksh, or fish)"
2373
- ;;
2374
- esac
2375
- }
2376
-
2377
- cmd_doctor() {
2378
- _status=0
2379
-
2380
- info "checking environment..."
2381
-
2382
- # Check POSIX utilities
2383
- for _cmd in mkdir rm cp mv ln cat sha256sum shasum stat cmp find; do
2384
- if command -v "$_cmd" >/dev/null 2>&1; then
2385
- printf ' ok: %s\n' "$_cmd"
2386
- else
2387
- case "$_cmd" in
2388
- sha256sum|shasum)
2389
- # Need at least one
2390
- if ! command -v sha256sum >/dev/null 2>&1 && ! command -v shasum >/dev/null 2>&1; then
2391
- printf ' FAIL: no SHA-256 utility (need sha256sum or shasum)\n'
2392
- _status=1
2393
- else
2394
- printf ' ok: sha256 (via %s)\n' "$(command -v sha256sum 2>/dev/null || command -v shasum 2>/dev/null)"
2395
- fi
2396
- ;;
2397
- *)
2398
- printf ' FAIL: missing required utility: %s\n' "$_cmd"
2399
- _status=1
2400
- ;;
2401
- esac
2402
- fi
2403
- done
2404
-
2405
- # Check XDG directories
2406
- for _dir in "$VALISE_XDG_DATA" "$VALISE_XDG_CONFIG" "$VALISE_XDG_STATE"; do
2407
- if [ -d "$_dir" ]; then
2408
- printf ' ok: directory exists: %s\n' "$_dir"
2409
- else
2410
- printf ' warn: directory missing (will create on install): %s\n' "$_dir"
2411
- fi
2412
- done
2413
-
2414
- # Check active symlink
2415
- if [ -L "$VALISE_ACTIVE_LINK" ]; then
2416
- _target=$(readlink_target "$VALISE_ACTIVE_LINK" 2>/dev/null || :)
2417
- if [ -d "$_target" ]; then
2418
- printf ' ok: active release: %s\n' "$_target"
2419
- else
2420
- printf ' FAIL: active symlink points to missing directory: %s\n' "$_target"
2421
- _status=1
2422
- fi
2423
- elif [ -e "$VALISE_ACTIVE_LINK" ]; then
2424
- printf ' FAIL: active pointer is not a symlink: %s\n' "$VALISE_ACTIVE_LINK"
2425
- _status=1
2426
- else
2427
- printf ' info: no active release configured\n'
2428
- fi
2429
-
2430
- # Platform check (informational only; install and variant use are portable
2431
- # POSIX and not gated on any particular uname).
2432
- _uname=$(uname -s 2>/dev/null || echo unknown)
2433
- printf ' platform: %s\n' "$_uname"
2434
-
2435
- if [ "$_status" -eq 0 ]; then
2436
- info "all checks passed"
2437
- else
2438
- die "some checks failed"
2439
- fi
2440
- }
2441
- cmd_verify_release_root() {
2442
- [ "$#" -eq 1 ] || die "usage: valise _verify-release-root <release-root>"
2443
- _verify_release_arg=$1
2444
- case "$_verify_release_arg" in
2445
- /*) : ;;
2446
- *) die "release root must be absolute" ;;
2447
- esac
2448
- [ -d "$_verify_release_arg" ] || die "release root is not a directory"
2449
- [ ! -L "$_verify_release_arg" ] || die "release root must not be a symlink"
2450
- _verify_release_canonical=$(cd "$_verify_release_arg" 2>/dev/null && pwd -P) || die "cannot resolve release root"
2451
- _verify_releases_canonical=$(cd "$VALISE_RELEASES_DIR" 2>/dev/null && pwd -P) || die "release storage is unavailable"
2452
- _verify_release_parent=$(cd "$(path_parent "$_verify_release_canonical")" 2>/dev/null && pwd -P) || die "release parent unavailable"
2453
- [ "$_verify_release_parent" = "$_verify_releases_canonical" ] || die "release root escapes release storage"
2454
- _verify_release_id=${_verify_release_canonical##*/}
2455
- case "$_verify_release_id" in
2456
- *[!0123456789abcdefABCDEF]*|'') die "release root identity is not a SHA-256 digest" ;;
2457
- esac
2458
- [ "${#_verify_release_id}" -eq 64 ] || die "release root identity is not a SHA-256 digest"
2459
- _verify_release_snapshot="$_verify_release_canonical/.valise-manifest"
2460
- [ -f "$_verify_release_snapshot" ] || die "release manifest snapshot is missing"
2461
- [ ! -L "$_verify_release_snapshot" ] || die "release manifest snapshot must not be a symlink"
2462
- prepare_manifest_rows "$_verify_release_snapshot" || die "cannot read release manifest snapshot"
2463
- _verify_release_rows=$_manifest_rows
2464
- validate_manifest "$_verify_release_rows" || die "invalid release manifest snapshot"
2465
- verify_release_dir "$_verify_release_canonical" "$_verify_release_rows" "$_verify_release_id"
2466
- printf '%s\n' "$_verify_release_canonical"
2467
- }
2468
-
2469
- cmd_verify_active() {
2470
- _verify_print_root=0
2471
- for _verify_arg do
2472
- case "$_verify_arg" in
2473
- --print-root) _verify_print_root=1 ;;
2474
- *) die "unknown verify-active option: $_verify_arg" ;;
2475
- esac
2476
- done
2477
- [ -L "$VALISE_ACTIVE_LINK" ] || die "active pointer is not a symlink"
2478
- _verify_active_target=$(readlink_target "$VALISE_ACTIVE_LINK" 2>/dev/null) || die "cannot read active pointer"
2479
- case "$_verify_active_target" in
2480
- /*) : ;;
2481
- *)
2482
- _verify_active_link_parent=$(cd "$(path_parent "$VALISE_ACTIVE_LINK")" 2>/dev/null && pwd -P) || die "active pointer parent unavailable"
2483
- _verify_active_target="$_verify_active_link_parent/$_verify_active_target"
2484
- ;;
2485
- esac
2486
- [ -d "$_verify_active_target" ] || die "active release target is not a directory"
2487
- _verify_active_root=$(cd "$_verify_active_target" 2>/dev/null && pwd -P) || die "cannot resolve active release root"
2488
- _verify_releases_root=$(cd "$VALISE_RELEASES_DIR" 2>/dev/null && pwd -P) || die "release root unavailable"
2489
- _verify_active_parent=$(cd "$(path_parent "$_verify_active_root")" 2>/dev/null && pwd -P) || die "active release parent unavailable"
2490
- [ "$_verify_active_parent" = "$_verify_releases_root" ] || die "active release escapes release root"
2491
- _verify_active_id=${_verify_active_root##*/}
2492
- case "$_verify_active_id" in
2493
- *[!0123456789abcdefABCDEF]*|'') die "active release identity is not a SHA-256 digest" ;;
2494
- esac
2495
- [ "${#_verify_active_id}" -eq 64 ] || die "active release identity is not a SHA-256 digest"
2496
- _verify_active_manifest="$_verify_active_root/.valise-manifest"
2497
- [ -f "$_verify_active_manifest" ] || die "active release manifest is missing"
2498
- [ ! -L "$_verify_active_manifest" ] || die "active release manifest must not be a symlink"
2499
- prepare_manifest_rows "$_verify_active_manifest" || die "cannot read active release manifest"
2500
- _verify_active_manifest_rows="$_manifest_rows"
2501
- validate_manifest "$_verify_active_manifest_rows" || die "invalid active release manifest"
2502
- verify_release_dir "$_verify_active_root" "$_verify_active_manifest_rows" "$_verify_active_id"
2503
- if [ "$_verify_print_root" -eq 1 ]; then
2504
- printf '%s\n' "$_verify_active_root"
2505
- fi
2506
- return 0
2507
- }
2508
- cmd_variant() {
2509
- _subcmd="${1:-list}"
2510
- case "$_subcmd" in
2511
- list)
2512
- if [ -d "$VALISE_RELEASES_DIR" ]; then
2513
- for _rel in "$VALISE_RELEASES_DIR"/*/; do
2514
- [ -d "$_rel" ] || continue
2515
- _name=$(basename "$_rel")
2516
- if [ -L "$VALISE_ACTIVE_LINK" ] && [ "$(readlink_target "$VALISE_ACTIVE_LINK" 2>/dev/null)" = "$_rel" ]; then
2517
- printf '* %s (active)\n' "$_name"
2518
- else
2519
- printf ' %s\n' "$_name"
2520
- fi
2521
- done
2522
- else
2523
- info "no releases installed"
2524
- fi
2525
- ;;
2526
- use)
2527
- _target="${2:-}"
2528
- [ -n "$_target" ] || die "usage: valise variant use <sha256>"
2529
- case "$_target" in
2530
- *[!A-Za-z0-9_.-]*|.*|*-|.-*|*..*) die "invalid release name: $_target" ;;
2531
- esac
2532
- _target_dir="$VALISE_RELEASES_DIR/$_target"
2533
- [ -e "$_target_dir" ] || die "release not found: $_target"
2534
- [ -d "$_target_dir" ] || die "release target is not a directory: $_target"
2535
- [ ! -L "$_target_dir" ] || die "release target must not be a symlink: $_target"
2536
- _releases_root=$(cd "$VALISE_RELEASES_DIR" 2>/dev/null && pwd -P) || die "release root unavailable"
2537
- _target_parent=$(cd "$(path_parent "$_target_dir")" 2>/dev/null && pwd -P) || die "release target parent unavailable"
2538
- case "$_target_parent/" in
2539
- "$_releases_root/"*) : ;;
2540
- *) die "release target escapes release root: $_target" ;;
33
+ case "$_valise_self" in
34
+ */*) _valise_self=${_valise_self%/*}/$_valise_link ;;
35
+ *) _valise_self=$_valise_link ;;
2541
36
  esac
2542
- _target_manifest="$_target_dir/.valise-manifest"
2543
- if [ -e "$_target_manifest" ] || [ -L "$_target_manifest" ]; then
2544
- [ -f "$_target_manifest" ] || die "release manifest snapshot is not a regular file"
2545
- [ ! -L "$_target_manifest" ] || die "release manifest snapshot must not be a symlink"
2546
- _manifest="$_target_manifest"
2547
- else
2548
- _manifest=$(locate_manifest) || die "cannot find profile-release.manifest to verify release"
2549
- fi
2550
- prepare_manifest_rows "$_manifest" || die "cannot snapshot profile-release.manifest"
2551
- _manifest="$_manifest_rows"
2552
- validate_manifest "$_manifest" || die "invalid profile-release.manifest schema or row"
2553
- verify_release_dir "$_target_dir" "$_manifest" "$_target"
2554
- _config_parent=$(path_parent "$VALISE_ACTIVE_LINK")
2555
- if [ ! -d "$_config_parent" ]; then
2556
- _mkdir_path=$(trusted_utility_path mkdir) || die "no trusted mkdir utility available"
2557
- "$_mkdir_path" -p "$_config_parent"
2558
- fi
2559
- acquire_lock
2560
- switch_active_link "$_target_dir"
2561
- release_lock
2562
- info "switched to release $_target"
2563
- ;;
2564
- *)
2565
- die "unknown variant subcommand: $_subcmd (use list or use)"
2566
37
  ;;
2567
38
  esac
39
+ done
40
+ case "$_valise_self" in
41
+ */*) _valise_self_dir=${_valise_self%/*} ;;
42
+ *) _valise_self_dir=. ;;
43
+ esac
44
+ _valise_engine_bin=$(cd "${_valise_self_dir:-/}" && pwd -P) || {
45
+ printf 'valise: error: cannot locate the valise engine from %s\n' "$0" >&2
46
+ exit 1
2568
47
  }
2569
-
2570
- cmd_install() {
2571
- for _arg do
2572
- case "$_arg" in
2573
- --help|-h) usage; return 0 ;;
2574
- --*) die "unknown install option: $_arg (usage: valise install)" ;;
2575
- esac
2576
- done
2577
-
2578
- _manifest_source=$(locate_manifest) || die "cannot find profile-release.manifest; run from repository root or installed tree"
2579
- _manifest_root=$(cd "$(path_parent "$_manifest_source")/../.." && pwd -P) || die "cannot resolve manifest source root"
2580
- prepare_manifest_rows "$_manifest_source" || die "cannot normalize profile-release.manifest"
2581
- _manifest="$_manifest_rows"
2582
- validate_manifest "$_manifest" || die "invalid profile-release.manifest schema or row"
2583
-
2584
- # Release identity is content-derived; the schema header is not an ID.
2585
- _release_id=$(file_sha256 "$_manifest") || die "no trusted SHA-256 utility available"
2586
- case "$_release_id" in
2587
- *[!0123456789abcdefABCDEF]*|'') die "invalid release ID derived from manifest" ;;
2588
- esac
2589
- [ "${#_release_id}" -eq 64 ] || die "invalid release ID derived from manifest"
2590
-
2591
- _target_dir="$VALISE_RELEASES_DIR/$_release_id"
2592
-
2593
- acquire_lock
2594
- _mkdir_path=$(trusted_utility_path mkdir) || die "no trusted mkdir utility available"
2595
- _chmod_path=$(trusted_utility_path chmod) || die "no trusted chmod utility available"
2596
- "$_mkdir_path" -p "$VALISE_XDG_CONFIG" "$VALISE_XDG_STATE" || die "cannot create valise configuration directories"
2597
- [ ! -L "$_target_dir" ] || die "release target must not be a symlink: $_release_id"
2598
-
2599
- if [ -e "$_target_dir" ] && [ ! -d "$_target_dir" ]; then
2600
- die "release path is not a directory: $_target_dir"
2601
- fi
2602
- if [ -d "$_target_dir" ]; then
2603
- _target_manifest="$_target_dir/.valise-manifest"
2604
- if [ -e "$_target_manifest" ] || [ -L "$_target_manifest" ]; then
2605
- [ -f "$_target_manifest" ] || die "release manifest snapshot is not a regular file"
2606
- [ ! -L "$_target_manifest" ] || die "release manifest snapshot must not be a symlink"
2607
- prepare_manifest_rows "$_target_manifest" || die "cannot snapshot release manifest"
2608
- _target_manifest="$_manifest_rows"
2609
- validate_manifest "$_target_manifest" || die "invalid release manifest snapshot"
2610
- verify_release_dir "$_target_dir" "$_target_manifest" "$_release_id"
2611
- else
2612
- verify_release_dir "$_target_dir" "$_manifest" "$_release_id"
2613
- fi
2614
- info "release $_release_id already installed and verified"
2615
- else
2616
- info "installing release $_release_id..."
2617
-
2618
- # Create target directories
2619
- "$_mkdir_path" -p "$VALISE_RELEASES_DIR" "$VALISE_XDG_CONFIG" "$VALISE_XDG_STATE"
2620
-
2621
- # Stage into temp directory first
2622
- _stage=$(trusted_mktemp dir "${TMPDIR:-/tmp}/valise-install.XXXXXX") || die "cannot create staging directory"
2623
- _cp_path=$(trusted_utility_path cp) || die "no trusted cp utility available"
2624
- "$_cp_path" -p "$_manifest" "$_stage/.valise-manifest" || die "failed to stage release manifest"
2625
- "$_chmod_path" 0444 "$_stage/.valise-manifest" || die "failed to seal release manifest"
2626
-
2627
- # Copy release files from manifest
2628
- # The manifest format is: destination source mode install_mode size sha256
2629
- while IFS="$(printf '\t')" read -r _dest _src _mode _imode _size _sha; do
2630
- [ -n "$_dest" ] || continue
2631
- case "$_dest" in \#*|shell-profile-release-manifest-v1|destination) continue ;; esac
2632
- case "$_src" in
2633
- ""|.|./*|*/.|*/./*|*//*|/*|*/../*|../*|*/..|..*) die "invalid manifest source path: $_src" ;;
2634
- esac
2635
- case "$_dest" in
2636
- ""|.|./*|*/.|*/./*|*//*|/*|*/../*|../*|*/..|..*) die "invalid manifest destination path: $_dest" ;;
2637
- esac
2638
- _src_path="$_manifest_root/$_src"
2639
- _dest_path="$_stage/$_dest"
2640
- [ -f "$_src_path" ] || die "manifest source missing: $_src"
2641
- source_path_is_physical "$_manifest_root" "$_src" || die "manifest source path contains a symlink: $_src"
2642
- [ ! -L "$_src_path" ] || die "manifest source must not be a symlink: $_src"
2643
- _src_parent=$(cd "$(path_parent "$_src_path")" 2>/dev/null && pwd -P) || die "manifest source parent missing: $_src"
2644
- case "$_src_parent/" in
2645
- "$_manifest_root/"*) : ;;
2646
- *) die "manifest source escapes source root: $_src" ;;
2647
- esac
2648
- [ "$(file_mode "$_src_path")" = "$_mode" ] || die "manifest source mode mismatch: $_src"
2649
- [ "$(file_bytes "$_src_path")" = "$_size" ] || die "manifest source byte count mismatch: $_src"
2650
- case "$_mode:$_imode" in
2651
- 0644:0444|0755:0555) : ;;
2652
- *) die "invalid immutable mode pair for $_dest" ;;
2653
- esac
2654
- [ -n "$_sha" ] || die "manifest digest missing: $_dest"
2655
- case "$_sha" in
2656
- *[!0123456789abcdefABCDEF]*) die "invalid manifest digest for $_dest" ;;
2657
- esac
2658
- [ "${#_sha}" -eq 64 ] || die "invalid manifest digest for $_dest"
2659
- _dest_parent=$(path_parent "$_dest_path")
2660
- "$_mkdir_path" -p "$_dest_parent"
2661
- "$_cp_path" -p "$_src_path" "$_dest_path" || die "failed to copy $_src"
2662
- "$_chmod_path" "$_imode" "$_dest_path" || die "failed to seal $_dest"
2663
- done < "${_manifest_parse:-$_manifest_rows}"
2664
-
2665
- # Verify staged files against manifest digests
2666
- _verify_ok=1
2667
- while IFS="$(printf '\t')" read -r _dest _src _mode _imode _size _sha; do
2668
- [ -n "$_dest" ] || continue
2669
- case "$_dest" in \#*|shell-profile-release-manifest-v1|destination) continue ;; esac
2670
- case "$_dest" in
2671
- ""|.|./*|*/.|*/./*|*//*|/*|*/../*|../*|*/..|..*) die "invalid manifest destination path: $_dest" ;;
2672
- esac
2673
- _staged_file="$_stage/$_dest"
2674
- [ -f "$_staged_file" ] || die "staged manifest file missing: $_dest"
2675
- [ "$(file_mode "$_staged_file")" = "$_imode" ] || die "staged install mode mismatch: $_dest"
2676
- [ "$(file_bytes "$_staged_file")" = "$_size" ] || die "staged byte count mismatch: $_dest"
2677
- [ -n "$_sha" ] || die "manifest digest missing: $_dest"
2678
- case "$_sha" in
2679
- *[!0123456789abcdefABCDEF]*) die "invalid manifest digest for $_dest" ;;
2680
- esac
2681
- [ "${#_sha}" -eq 64 ] || die "invalid manifest digest for $_dest"
2682
- _actual=$(file_sha256 "$_staged_file") || die "no trusted SHA-256 utility available"
2683
- _expected=$(printf '%s' "$_sha" | lower_hex) || die "no trusted tr utility available"
2684
- if [ "$_actual" != "$_expected" ]; then
2685
- die "digest mismatch for $_dest: expected $_sha got $_actual"
2686
- fi
2687
- done < "${_manifest_parse:-$_manifest_rows}"
2688
-
2689
- # Seal all release directories; files already received their declared
2690
- # immutable mode while being staged. Never publish an incompletely sealed
2691
- # tree.
2692
- seal_tree "$_stage" || die "failed to seal release directories"
2693
-
2694
- # Publish through a temporary sibling, then atomically rename the
2695
- # complete immutable tree into place. The EXIT/signal cleanup removes any
2696
- # incomplete sibling before it can poison this release ID.
2697
- _publish_tmp="$VALISE_RELEASES_DIR/.valise-release.$_release_id.$$"
2698
- [ ! -e "$_publish_tmp" ] && [ ! -L "$_publish_tmp" ] || die "release publication temporary path already exists"
2699
- "$_cp_path" -rp "$_stage" "$_publish_tmp" || die "failed to publish release"
2700
- seal_tree "$_publish_tmp" || die "failed to seal published release"
2701
- verify_release_dir "$_publish_tmp" "$_manifest" "$_release_id"
2702
- [ ! -e "$_target_dir" ] && [ ! -L "$_target_dir" ] || die "release target appeared during publication"
2703
- _mv_path=$(trusted_utility_path mv) || die "no trusted mv utility available"
2704
- "$_mv_path" "$_publish_tmp" "$_target_dir" || die "failed to publish release"
2705
- _publish_tmp=""
2706
- [ -d "$_target_dir" ] || die "published release directory is missing"
2707
- verify_release_dir "$_target_dir" "$_manifest" "$_release_id"
2708
- remove_tree "$_stage" || die "failed to remove staging directory"
2709
- _stage=""
2710
- info "release $_release_id installed"
48
+ VALISE_CLI_DIR="${_valise_engine_bin%/}/../lib/cli"
49
+ for _valise_part in usage common store fish-hook integration commands lifecycle devtools project; do
50
+ if [ ! -f "$VALISE_CLI_DIR/$_valise_part.sh" ]; then
51
+ printf 'valise: error: incomplete installation: missing lib/cli/%s.sh\n' "$_valise_part" >&2
52
+ exit 1
2711
53
  fi
54
+ . "$VALISE_CLI_DIR/$_valise_part.sh"
55
+ done
56
+ unset _valise_part _valise_self _valise_self_dir _valise_link
2712
57
 
2713
- # Update active symlink atomically without clobbering a non-symlink path.
2714
- if [ ! -L "$VALISE_ACTIVE_LINK" ] || [ "$(readlink_target "$VALISE_ACTIVE_LINK" 2>/dev/null)" != "$_target_dir" ]; then
2715
- acquire_lock
2716
- if [ -e "$VALISE_ACTIVE_LINK" ] && [ ! -L "$VALISE_ACTIVE_LINK" ]; then
2717
- release_lock
2718
- die "active path exists and is not a symlink: $VALISE_ACTIVE_LINK"
2719
- fi
2720
- switch_active_link "$_target_dir"
2721
- release_lock
2722
- info "active release set to $_release_id"
2723
- fi
2724
-
2725
- # Deploy the Fish conf.d hook when Fish is available. Installed releases
2726
- # currently expose the generated Fish plan; older releases may expose the
2727
- # project Fish entrypoint, so the emitted integration handles both.
2728
- _fish_path=$(trusted_utility_path fish 2>/dev/null || :)
2729
- if [ -n "$_fish_path" ]; then
2730
- _fish_conf_dir="${XDG_CONFIG_HOME:-$HOME/.config}/fish/conf.d"
2731
- _fish_hook="$_fish_conf_dir/valise.fish"
2732
- _mkdir_path=$(trusted_utility_path mkdir) || die "no trusted mkdir utility available"
2733
- "$_mkdir_path" -p "$_fish_conf_dir" || die "cannot create Fish configuration directory"
2734
- [ ! -L "$_fish_hook" ] || die "Fish hook path must not be a symlink: $_fish_hook"
2735
- if [ -d "$_fish_hook" ]; then
2736
- die "Fish hook path is a directory: $_fish_hook"
2737
- fi
2738
- # Use the platform mktemp in the destination directory. Its exclusive
2739
- # creation makes a pre-created predictable symlink unable to redirect the
2740
- # shell redirection below into an attacker-selected victim.
2741
- _hook_tmp=$(trusted_mktemp_at "$_fish_conf_dir" file "$_fish_conf_dir/.valise-hook.XXXXXX") || die "cannot create Fish hook staging file"
2742
- [ -f "$_hook_tmp" ] && [ ! -L "$_hook_tmp" ] || die "Fish hook staging path is unsafe"
2743
- {
2744
- printf '%s\n' \
2745
- "# Managed by valise install — do not edit." \
2746
- "# This hook loads the active valise release for Fish sessions."
2747
- print_fish_integration
2748
- } >"$_hook_tmp" || die "cannot write Fish hook"
2749
- _chmod_path=$(trusted_utility_path chmod) || die "no trusted chmod utility available"
2750
- "$_chmod_path" 0644 "$_hook_tmp" || die "cannot set Fish hook mode"
2751
- _cat_path=$(trusted_utility_path cat) || die "no trusted cat utility available"
2752
- _hook_expected=$("$_cat_path" "$_hook_tmp") || die "cannot read Fish hook staging file"
2753
- _mv_path=$(trusted_utility_path mv) || die "no trusted mv utility available"
2754
- # mv -f uses rename(2) which atomically replaces a regular file
2755
- # destination on both BSD and GNU systems. The hook path was verified
2756
- # non-symlink above, so no explicit removal is needed — mv -f alone
2757
- # preserves atomicity.
2758
- "$_mv_path" -f "$_hook_tmp" "$_fish_hook" || die "cannot publish Fish hook"
2759
- _hook_tmp=""
2760
- [ -f "$_fish_hook" ] || die "Fish hook was not published"
2761
- [ "$(file_mode "$_fish_hook")" = 0644 ] || die "Fish hook mode mismatch"
2762
- _hook_actual=$("$_cat_path" "$_fish_hook") || die "cannot read published Fish hook"
2763
- [ "$_hook_actual" = "$_hook_expected" ] || die "published Fish hook contents mismatch"
2764
- info "Fish hook deployed: $_fish_hook"
2765
- fi
2766
-
2767
- # Deploy POSIX shell integration to the platform-appropriate profile file.
2768
- # macOS: Terminal.app and iTerm2 open every window/tab as a login shell,
2769
- # so .bash_profile / .zprofile is sourced per terminal.
2770
- # Linux: terminal emulators open non-login interactive shells, so
2771
- # .bashrc / .zshrc / .kshrc is sourced per terminal.
2772
- _posix_shell="${SHELL:-}"
2773
- _posix_shell_name=""
2774
- case "$_posix_shell" in
2775
- */bash|bash) _posix_shell_name=bash ;;
2776
- */zsh|zsh) _posix_shell_name=zsh ;;
2777
- */ksh|ksh) _posix_shell_name=ksh ;;
2778
- esac
2779
- if [ -n "$_posix_shell_name" ] && [ -n "${HOME:-}" ]; then
2780
- _posix_platform=$(trusted_uname -s 2>/dev/null || echo unknown)
2781
- _posix_profile=""
2782
- case "$_posix_platform" in
2783
- Darwin)
2784
- case "$_posix_shell_name" in
2785
- bash) _posix_profile="$HOME/.bash_profile" ;;
2786
- zsh) _posix_profile="$HOME/.zprofile" ;;
2787
- ksh) _posix_profile="$HOME/.kshrc" ;;
2788
- esac
2789
- ;;
2790
- *)
2791
- case "$_posix_shell_name" in
2792
- bash) _posix_profile="$HOME/.bashrc" ;;
2793
- zsh) _posix_profile="$HOME/.zshrc" ;;
2794
- ksh) _posix_profile="$HOME/.kshrc" ;;
2795
- esac
2796
- ;;
2797
- esac
2798
- if [ -n "$_posix_profile" ]; then
2799
- if [ -L "$_posix_profile" ]; then
2800
- info "shell integration skipped: $_posix_profile is a symlink (managed externally)"
2801
- else
2802
- _posix_marker="managed by valise install"
2803
- _posix_already=0
2804
- if [ -f "$_posix_profile" ]; then
2805
- _awk_path=$(trusted_utility_path awk) || die "no trusted awk utility available"
2806
- if "$_awk_path" -v m="$_posix_marker" 'index($0,m){found=1;exit} END{exit !found}' "$_posix_profile" 2>/dev/null; then
2807
- _posix_already=1
2808
- fi
2809
- fi
2810
- if [ "$_posix_already" -eq 1 ]; then
2811
- info "shell integration already present: $_posix_profile"
2812
- else
2813
- _posix_active_literal=$(shell_quote "$VALISE_ACTIVE_LINK") || die "cannot quote active link path"
2814
- _posix_profile_dir=$(path_parent "$_posix_profile")
2815
- if [ ! -d "$_posix_profile_dir" ]; then
2816
- _mkdir_path=$(trusted_utility_path mkdir) || die "no trusted mkdir utility available"
2817
- "$_mkdir_path" -p "$_posix_profile_dir" || die "cannot create profile directory: $_posix_profile_dir"
2818
- fi
2819
- _posix_tmp=$(trusted_mktemp_at "$_posix_profile_dir" file "$_posix_profile_dir/.valise-profile.XXXXXX") || die "cannot create profile staging file"
2820
- [ -f "$_posix_tmp" ] && [ ! -L "$_posix_tmp" ] || die "profile staging path is unsafe"
2821
- if [ -f "$_posix_profile" ]; then
2822
- _cat_path=$(trusted_utility_path cat) || die "no trusted cat utility available"
2823
- "$_cat_path" "$_posix_profile" > "$_posix_tmp" || die "cannot copy existing profile"
2824
- printf '\n' >> "$_posix_tmp"
2825
- fi
2826
- {
2827
- printf '%s\n' "# valise shell integration — $_posix_marker"
2828
- printf '%s\n' "_valise_active_link=${_posix_active_literal}"
2829
- printf '%s\n' "if [ -L \"\$_valise_active_link/entrypoints/profile.sh\" ] || [ -f \"\$_valise_active_link/entrypoints/profile.sh\" ]; then"
2830
- printf '%s\n' " _valise_active=\$(cd \"\$_valise_active_link\" 2>/dev/null && pwd -P)"
2831
- printf '%s\n' " if [ -n \"\$_valise_active\" ]; then"
2832
- printf '%s\n' " VALISE_ROOT=\"\$_valise_active\""
2833
- printf '%s\n' " . \"\$_valise_active/entrypoints/profile.sh\""
2834
- printf '%s\n' " fi"
2835
- printf '%s\n' " unset _valise_active"
2836
- printf '%s\n' "fi"
2837
- printf '%s\n' "unset _valise_active_link"
2838
- } >> "$_posix_tmp" || die "cannot write profile snippet"
2839
- _chmod_path=$(trusted_utility_path chmod) || die "no trusted chmod utility available"
2840
- if [ -f "$_posix_profile" ]; then
2841
- _posix_existing_mode=$(file_mode "$_posix_profile")
2842
- [ -n "$_posix_existing_mode" ] || die "cannot read existing profile mode: $_posix_profile"
2843
- "$_chmod_path" "$_posix_existing_mode" "$_posix_tmp" || die "cannot preserve profile mode"
2844
- else
2845
- "$_chmod_path" 0644 "$_posix_tmp" || die "cannot set profile mode"
2846
- fi
2847
- _mv_path=$(trusted_utility_path mv) || die "no trusted mv utility available"
2848
- "$_mv_path" -f "$_posix_tmp" "$_posix_profile" || die "cannot publish profile snippet"
2849
- _posix_tmp=""
2850
- info "shell integration deployed: $_posix_profile"
2851
- fi
2852
- fi
2853
- fi
2854
- fi
2855
-
2856
- info "installation complete"
2857
- info "run 'valise init' to print the shell integration snippet for manual setup"
2858
- }
58
+ # --- Main dispatch ---
2859
59
 
2860
- cmd_make_manifest() {
2861
- _mm_tree=""
2862
- _mm_out=""
2863
- _mm_want_out=0
2864
- for _mm_arg do
2865
- case "$_mm_arg" in
2866
- --output) _mm_want_out=1 ;;
2867
- --output=*)
2868
- _mm_out=${_mm_arg#--output=}
2869
- [ -n "$_mm_out" ] || die "usage: valise make-manifest <tree> [--output <file>]"
2870
- ;;
2871
- --help|-h) printf '%s\n' "usage: valise make-manifest <tree> [--output <file>]"; return 0 ;;
2872
- --*) die "unknown make-manifest option: $_mm_arg" ;;
2873
- *)
2874
- if [ "$_mm_want_out" -eq 1 ]; then
2875
- _mm_out=$_mm_arg
2876
- _mm_want_out=0
2877
- elif [ -n "$_mm_tree" ]; then
2878
- die "usage: valise make-manifest <tree> [--output <file>]"
2879
- else
2880
- _mm_tree=$_mm_arg
2881
- fi
2882
- ;;
2883
- esac
2884
- done
2885
- [ "$_mm_want_out" -eq 0 ] || die "usage: valise make-manifest <tree> [--output <file>]"
2886
- [ -n "$_mm_tree" ] || die "usage: valise make-manifest <tree> [--output <file>]"
2887
- [ -d "$_mm_tree" ] || die "manifest tree is not a directory: $_mm_tree"
2888
- _mm_root=$(cd "$_mm_tree" && pwd -P) || die "cannot resolve manifest tree: $_mm_tree"
2889
- _mm_default_out="$_mm_root/shell/install/profile-release.manifest"
2890
- if [ -z "$_mm_out" ]; then
2891
- _mm_out="$_mm_default_out"
2892
- fi
2893
- case "$_mm_out" in
2894
- /*) : ;;
2895
- *)
2896
- while :; do
2897
- case "$_mm_out" in
2898
- ./*) _mm_out=${_mm_out#./} ;;
2899
- *) break ;;
2900
- esac
2901
- done
2902
- _mm_cwd=$(pwd -P) || die "cannot resolve working directory"
2903
- _mm_out="$_mm_cwd/$_mm_out"
60
+ # -C <dir> runs the command as if valise had been started in dir.
61
+ while [ "$#" -gt 0 ]; do
62
+ case "$1" in
63
+ -C)
64
+ [ "$#" -ge 2 ] && [ -n "$2" ] || die "-C needs a directory"
65
+ cd "$2" 2>/dev/null || die "cannot change to directory: $2"
66
+ shift 2
67
+ ;;
68
+ -C*)
69
+ cd "${1#-C}" 2>/dev/null || die "cannot change to directory: ${1#-C}"
70
+ shift
2904
71
  ;;
72
+ *) break ;;
2905
73
  esac
2906
- _mm_out_dir=$(path_parent "$_mm_out") || die "cannot resolve manifest parent"
2907
- _mm_mkdir_path=$(trusted_utility_path mkdir) || die "no trusted mkdir utility available"
2908
- "$_mm_mkdir_path" -p "$_mm_out_dir" || die "cannot create manifest directory: $_mm_out_dir"
2909
- _mm_find_path=$(trusted_utility_path find) || die "no trusted find utility available"
2910
- _mm_sort_path=$(trusted_utility_path sort) || die "no trusted sort utility available"
2911
- # Symlinks never enter a sealed release: find without -L reports them as
2912
- # -type l, so any symlink anywhere under the tree fails closed here.
2913
- _mm_links=$("$_mm_find_path" "$_mm_root" -type l -print) || die "cannot scan manifest tree: $_mm_root"
2914
- [ -z "$_mm_links" ] || die "manifest tree must not contain symlinks: $_mm_root"
2915
- _mm_list=$("$_mm_find_path" "$_mm_root" -type f -print) || die "cannot list manifest tree: $_mm_root"
2916
- _mm_tmp=$(trusted_mktemp_at "$_mm_out_dir" file "$_mm_out_dir/.valise-manifest.XXXXXX") || die "cannot stage manifest"
2917
- _mm_tab=$(printf '\t')
2918
- _mm_nl='
2919
- '
2920
- _mm_count=0
2921
- printf '%s\n' "shell-profile-release-manifest-v1" >"$_mm_tmp" || die "cannot write manifest"
2922
- printf 'destination\tsource\tsource_mode\tinstall_mode\tbytes\tsha256\n' >>"$_mm_tmp" || die "cannot write manifest"
2923
- _mm_sorted=$(printf '%s\n' "$_mm_list" | LC_ALL=C "$_mm_sort_path") || die "cannot sort manifest tree listing"
2924
- while IFS= read -r _mm_full || [ -n "$_mm_full" ]; do
2925
- [ -n "$_mm_full" ] || continue
2926
- # The manifest describes the tree payload, never itself: both the
2927
- # requested output and the default output path stay out of the rows so
2928
- # consecutive runs over an unchanged tree are byte-identical.
2929
- [ "$_mm_full" != "$_mm_out" ] || continue
2930
- [ "$_mm_full" != "$_mm_default_out" ] || continue
2931
- [ "$_mm_full" != "$_mm_tmp" ] || continue
2932
- _mm_rel=${_mm_full#"$_mm_root"/}
2933
- # Same name rules as validate_manifest: the schema charset plus no
2934
- # tab/newline (row delimiters) and no dot segments. Anything else
2935
- # fails here naming the file instead of at validation time.
2936
- case "$_mm_rel" in
2937
- *"$_mm_nl"*|*"$_mm_tab"*|*[!A-Za-z0-9._/-]*|"#"*|.|..|./*|../*|*/.|*/..|*/./*|*/../*) die "manifest tree file has an unrepresentable name: $_mm_full" ;;
2938
- esac
2939
- _mm_mode=$(file_mode "$_mm_full") || die "cannot read file mode: $_mm_full"
2940
- case "$_mm_mode" in
2941
- 0644) _mm_imode=0444 ;;
2942
- 0755) _mm_imode=0555 ;;
2943
- *) die "manifest tree file has unsupported mode $_mm_mode (normalize to 0644 or 0755): $_mm_full" ;;
2944
- esac
2945
- _mm_bytes=$(file_bytes "$_mm_full") || die "cannot read file size: $_mm_full"
2946
- _mm_sha=$(file_sha256 "$_mm_full") || die "no trusted SHA-256 utility available"
2947
- printf '%s\t%s\t%s\t%s\t%s\t%s\n' "$_mm_rel" "$_mm_rel" "$_mm_mode" "$_mm_imode" "$_mm_bytes" "$_mm_sha" >>"$_mm_tmp" || die "cannot write manifest"
2948
- _mm_count=$((_mm_count + 1))
2949
- done <<_MM_SORTED_EOF
2950
- $_mm_sorted
2951
- _MM_SORTED_EOF
2952
- [ "$_mm_count" -gt 0 ] || die "manifest tree contains no files: $_mm_root"
2953
- validate_manifest "$_mm_tmp" || die "generated manifest failed validation"
2954
- _mm_mv_path=$(trusted_utility_path mv) || die "no trusted mv utility available"
2955
- "$_mm_mv_path" -f "$_mm_tmp" "$_mm_out" || die "cannot publish manifest: $_mm_out"
2956
- _mm_chmod_path=$(trusted_utility_path chmod) || die "no trusted chmod utility available"
2957
- "$_mm_chmod_path" 0644 "$_mm_out" || die "cannot set manifest mode: $_mm_out"
2958
- _mm_tmp=""
2959
- info "manifest written: $_mm_out ($_mm_count files)"
2960
- }
2961
-
2962
- cmd_compile() {
2963
- _out_dir=""
2964
- _variant="workstation-full"
2965
- _bundle=""
2966
- _bundle_requested=0
2967
- for _arg do
2968
- case "$_arg" in
2969
- --variant=*) _variant="${_arg#--variant=}" ;;
2970
- --bundle=*) _bundle="${_arg#--bundle=}"; _bundle_requested=1 ;;
2971
- --help|-h) usage; return 0 ;;
2972
- *) [ -z "$_out_dir" ] && _out_dir="$_arg" ;;
2973
- esac
2974
- done
2975
- [ -n "$_out_dir" ] || die "usage: valise compile [--bundle=<name>] [--variant=<name>] <output-dir>"
2976
- _script_dir=$(cd "$(path_parent "$0")" && pwd -P)
2977
- _awk_compiler="$_script_dir/../lib/compiler.awk"
2978
- [ -f "$_awk_compiler" ] || die "compiler.awk not found at $_awk_compiler"
2979
-
2980
- # Find source tree root (look for shell/release/ relative to script or cwd)
2981
- _src_root=""
2982
- for _candidate in "$_script_dir/../../.." "$_script_dir/../.." "$_script_dir/.." "."; do
2983
- if [ -f "$_candidate/shell/release/module-registry.tsv" ]; then
2984
- _src_root=$(cd "$_candidate" && pwd -P)
2985
- break
2986
- fi
2987
- done
2988
- [ -n "$_src_root" ] || die "cannot find source tree (need shell/release/module-registry.tsv)"
2989
-
2990
- _registry="$_src_root/shell/release/module-registry.tsv"
2991
- _roots_json="$_src_root/shell/release/profile-release.json"
2992
- _release_compiler="$_src_root/hack/compile-shell-profile-release.py"
2993
- [ -f "$_release_compiler" ] || die "release compiler not found: $_release_compiler"
2994
- _prelude="$_src_root/submodule/valise-sh/lib/capabilities.sh"
2995
- _variants_file="$_src_root/shell/release/install-variants"
2996
- _variant_matches=$(awk -F'\t' -v v="$_variant" '$1 == v { count++ } END { print count + 0 }' "$_variants_file")
2997
- [ "$_variant_matches" -eq 1 ] || die "unknown or ambiguous variant: $_variant"
2998
- # Extract prelude function names
2999
- # Extract sp_cap_ functions matching Python SHELL_FUNCTION_DEFINITION regex
3000
- # Pattern: ^name() { (file-appearance order, no sorting)
3001
- [ -r "$_prelude" ] || die "capabilities prelude not found: $_prelude"
3002
- _prelude_fns=$(sed -n 's/^\([a-z_][a-zA-Z0-9_]*\)()[[:space:]]*{.*/\1/p' "$_prelude" | grep '^sp_cap_' | tr '\n' ' ')
3003
- [ -n "$_prelude_fns" ] || die "capabilities prelude contains no sp_cap_ functions"
3004
-
3005
- # Extract exclusion list and validate each exclusion against the identity
3006
- # represented by install-variants. Bare names are project module identities;
3007
- # qualified names may explicitly name another registry source. Do this before
3008
- # creating output so all fail-closed validation paths are transactional.
3009
- _exclude_list=""
3010
- if [ -f "$_variants_file" ]; then
3011
- _exclude_list=$(awk -F' ' -v v="$_variant" '$1 == v { print $3 }' "$_variants_file")
3012
- fi
3013
- if [ -z "$_exclude_list" ] && [ "$_variant" != "workstation-full" ]; then
3014
- info "warning: variant $_variant not found in install-variants, using default"
3015
- fi
3016
- for _excluded_module in $_exclude_list; do
3017
- _excluded_count=$(awk -F ' ' -v wanted="$_excluded_module" '
3018
- NR > 1 {
3019
- if (index(wanted, "@")) {
3020
- split(wanted, parts, "@"); match_row = ($1 == parts[1] && $11 == parts[2])
3021
- } else { match_row = ($1 == wanted && $11 == "shell/module.d") }
3022
- if (match_row) count++
3023
- }
3024
- END { print count + 0 }' "$_registry")
3025
- [ "$_excluded_count" -eq 1 ] ||
3026
- die "variant $_variant excludes unknown or ambiguous registry module: $_excluded_module"
3027
- done
3028
-
3029
- if [ "$_bundle_requested" -eq 1 ]; then
3030
- [ -n "$_bundle" ] || die "bundle name must not be empty"
3031
- # Validate bundle identity before creating the output transaction.
3032
- python3 "$_release_compiler" --root "$_src_root" --bundle-roots bash --bundle "$_bundle" >/dev/null ||
3033
- die "failed to resolve bundle roots for bash"
3034
- fi
3035
-
3036
- # Compile into a private sibling directory. A non-empty destination is
3037
- # rejected before any plan is generated, so a failed compile can never leave
3038
- # a partially replaced output tree. An empty existing directory is supported
3039
- # for callers that pre-create their destination; it is replaced only after
3040
- # every plan has compiled successfully. Trailing slashes are normalized so
3041
- # "out/" and "out" are the same destination (see path_parent).
3042
- while [ "$_out_dir" != "/" ] && [ "${_out_dir%/}" != "$_out_dir" ]; do
3043
- _out_dir=${_out_dir%/}
3044
- done
3045
- _out_parent=$(path_parent "$_out_dir")
3046
- _mkdir_path=$(trusted_utility_path mkdir) || die "no trusted mkdir utility available"
3047
- if [ ! -d "$_out_parent" ]; then
3048
- "$_mkdir_path" -p "$_out_parent" || die "cannot create output parent directory"
3049
- fi
3050
- _compile_output_existed=0
3051
- if [ -e "$_out_dir" ] || [ -L "$_out_dir" ]; then
3052
- [ -d "$_out_dir" ] && [ ! -L "$_out_dir" ] || die "output path is not a directory: $_out_dir"
3053
- _compile_output_existed=1
3054
- _compile_output_empty=1
3055
- for _existing_entry in "$_out_dir"/* "$_out_dir"/.[!.]* "$_out_dir"/..?*; do
3056
- if [ -e "$_existing_entry" ] || [ -L "$_existing_entry" ]; then
3057
- _compile_output_empty=0
3058
- break
3059
- fi
3060
- done
3061
- [ "$_compile_output_empty" -eq 1 ] || die "output directory must be empty: $_out_dir"
3062
- fi
3063
- _stage=$(trusted_mktemp_at "$_out_parent" dir "$_out_parent/.valise-compile.XXXXXX") ||
3064
- die "cannot create compile staging directory"
3065
-
3066
- # Fish plans require native Fish syntax; awk compiler emits POSIX sh only.
3067
- # Python compiler (hack/compile-shell-profile-release.py) handles Fish correctly.
3068
- info "fish plan generation requires Python compiler (awk compiler is POSIX-only)"
3069
- for _shell in bash zsh ksh wrapper_lifecycle; do
3070
- # Extract roots for this shell from JSON using POSIX tools
3071
- if [ "$_bundle_requested" -eq 1 ]; then
3072
- _roots=$(python3 "$_release_compiler" --root "$_src_root" --bundle-roots "$_shell" --bundle "$_bundle") || die "failed to resolve bundle roots for $_shell"
3073
- else
3074
- _roots=$(python3 "$_release_compiler" --root "$_src_root" --bundle-roots "$_shell") || die "failed to resolve bundle roots for $_shell"
3075
- fi
3076
-
3077
- [ -n "$_roots" ] || continue
3078
-
3079
- # wrapper_lifecycle uses bash shell filtering (matches Python compiler)
3080
- _effective_shell="$_shell"
3081
- [ "$_shell" != "wrapper_lifecycle" ] || _effective_shell="bash"
3082
-
3083
- _plan_file="installed-modules.$_shell"
3084
- [ "$_shell" != "wrapper_lifecycle" ] || _plan_file="wrapper-lifecycle.bash"
3085
-
3086
- # Filter registry for modules matching this shell and build input stream
3087
- {
3088
- # Filter seeds through exclusion list
3089
- _filtered_roots=""
3090
- for _seed in $_roots; do
3091
- _seed_name=${_seed%@*}
3092
- _seed_source="shell/module.d"
3093
- case "$_seed" in *@*) _seed_source=${_seed#*@} ;; esac
3094
- _excluded=0
3095
- for _ex in $_exclude_list; do
3096
- case "$_ex" in
3097
- *@*) [ "$_seed" = "$_ex" ] && _excluded=1 ;;
3098
- *) [ "$_seed_name" = "$_ex" ] && [ "$_seed_source" = "shell/module.d" ] && _excluded=1 ;;
3099
- esac
3100
- [ "$_excluded" -eq 1 ] && break
3101
- done
3102
- [ "$_excluded" -eq 1 ] || _filtered_roots="$_filtered_roots $_seed"
3103
- done
3104
- _filtered_roots="${_filtered_roots# }"
3105
- printf 'SEED:%s
3106
- ' "$_filtered_roots"
3107
- printf 'PRELUDE:%s
3108
- ' "$_prelude_fns"
3109
- # Preprocess the registry with source-qualified identities. This keeps
3110
- # duplicate module names distinct and gives contribution bodies their
3111
- # installed layer prefix.
3112
- awk -F' ' -v shell="$_effective_shell" -v excludes="$_exclude_list" '
3113
- function shell_matches(shells, wanted, count, i, values) {
3114
- if (shells == "any") return 1
3115
- count = split(shells, values, " ")
3116
- for (i = 1; i <= count; i++) {
3117
- if (values[i] == wanted || values[i] == "sh") return 1
3118
- }
3119
- return 0
3120
- }
3121
- NR == 1 { next }
3122
- {
3123
- name = $1; msrc = $11
3124
- if (name == "" || msrc == "shell/helpers" || !shell_matches($6, shell)) next
3125
- identity = name "@" msrc
3126
- row_exists[identity] = 1
3127
- row_name[identity] = name
3128
- row_source[identity] = msrc
3129
- row_req[identity] = $4
3130
- row_load[identity] = $9
3131
- }
3132
- END {
3133
- for (identity in row_exists) {
3134
- name = row_name[identity]; source = row_source[identity]
3135
- excluded = 0
3136
- if (source == "shell/module.d" && excludes != "") {
3137
- n_ex = split(excludes, ex_arr, " ")
3138
- for (ei = 1; ei <= n_ex; ei++) {
3139
- if (ex_arr[ei] == name || ex_arr[ei] == identity) { excluded = 1; break }
3140
- }
3141
- }
3142
- if (excluded) continue
3143
- req = ""
3144
- n_req = split(row_req[identity], req_arr, " ")
3145
- for (ri = 1; ri <= n_req; ri++) {
3146
- dep = req_arr[ri]
3147
- if (dep == "") continue
3148
- candidate = dep "@" source
3149
- if (candidate in row_exists) { resolved = candidate }
3150
- else {
3151
- resolved = dep; candidate_count = 0
3152
- for (candidate_key in row_exists) {
3153
- if (row_name[candidate_key] == dep) { resolved = candidate_key; candidate_count++ }
3154
- }
3155
- if (candidate_count != 1) resolved = dep
3156
- }
3157
- req = req (req == "" ? "" : " ") resolved
3158
- }
3159
- load_path = row_load[identity]
3160
- if (source == "shell/layers/contrib/module.d") load_path = "layers/contrib/" load_path
3161
- printf "MOD:%s\t%s\t%s\n", identity, req, load_path
3162
- }
3163
- }
3164
- ' "$_registry"
3165
- } | awk -v target_shell="$_effective_shell" -v plan_name="$_shell" -f "$_awk_compiler" > "$_stage/$_plan_file"
3166
-
3167
- info "compiled plan for $_shell"
3168
- done
3169
-
3170
- _mv_path=$(trusted_utility_path mv) || die "no trusted mv utility available"
3171
- if [ "$_compile_output_existed" -eq 1 ]; then
3172
- _rmdir_path=$(trusted_utility_path rmdir) || die "no trusted rmdir utility available"
3173
- "$_rmdir_path" "$_out_dir" || die "cannot clear empty output directory"
3174
- fi
3175
- if ! "$_mv_path" "$_stage" "$_out_dir"; then
3176
- if [ "$_compile_output_existed" -eq 1 ] && [ ! -e "$_out_dir" ] && [ ! -L "$_out_dir" ]; then
3177
- "$_mkdir_path" "$_out_dir" 2>/dev/null || :
3178
- fi
3179
- die "cannot publish compiled plans"
3180
- fi
3181
- _stage=""
3182
- }
3183
-
3184
-
3185
- cmd_explain_variant() {
3186
- _variant="${1:-workstation-full}"
3187
- _script_dir=$(cd "$(path_parent "$0")" && pwd -P)
3188
- _src_root=""
3189
- for _candidate in "$_script_dir/../../.." "$_script_dir/../.." "$_script_dir/.." "."; do
3190
- if [ -f "$_candidate/shell/release/install-variants" ]; then
3191
- _src_root=$(cd "$_candidate" && pwd -P)
3192
- break
3193
- fi
3194
- done
3195
- [ -n "$_src_root" ] || die "cannot find source tree"
3196
-
3197
- _variants_file="$_src_root/shell/release/install-variants"
3198
- [ -f "$_variants_file" ] || die "install-variants file not found"
3199
-
3200
- _release_compiler="$_src_root/hack/compile-shell-profile-release.py"
3201
- [ -f "$_release_compiler" ] || die "release compiler not found: $_release_compiler"
3202
-
3203
- _exclude_list=$(awk -F' ' -v v="$_variant" '$1 == v { print $3 }' "$_variants_file")
3204
- _desc=$(awk -F' ' -v v="$_variant" '$1 == v { print $2 }' "$_variants_file")
3205
-
3206
- printf 'Variant: %s
3207
- ' "$_variant"
3208
- printf 'Description: %s
3209
- ' "${_desc:-unknown}"
3210
- printf 'Excluded modules: %s
3211
- ' "${_exclude_list:-none (default)}"
3212
- printf '
3213
- Per-shell impact:
3214
- '
3215
-
3216
- for _shell in bash zsh ksh wrapper_lifecycle fish; do
3217
- _roots=$(python3 "$_release_compiler" --root "$_src_root" --bundle-roots "$_shell") || continue
3218
-
3219
- _count=0
3220
- _excluded=0
3221
- for _seed in $_roots; do
3222
- _is_ex=0
3223
- _seed_name=${_seed%@*}
3224
- _seed_source="shell/module.d"
3225
- case "$_seed" in *@*) _seed_source=${_seed#*@} ;; esac
3226
- for _ex in $_exclude_list; do
3227
- case "$_ex" in
3228
- *@*) [ "$_seed" = "$_ex" ] && _is_ex=1 ;;
3229
- *) [ "$_seed_name" = "$_ex" ] && [ "$_seed_source" = "shell/module.d" ] && _is_ex=1 ;;
3230
- esac
3231
- [ "$_is_ex" -eq 1 ] && break
3232
- done
3233
- if [ "$_is_ex" -eq 1 ]; then
3234
- _excluded=$((_excluded+1))
3235
- else
3236
- _count=$((_count+1))
3237
- fi
3238
- done
3239
- printf ' %s: %d roots (%d excluded)
3240
- ' "$_shell" "$_count" "$_excluded"
3241
- done
3242
- }
3243
-
3244
- cmd_explain_bundles() {
3245
- _script_dir=$(cd "$(path_parent "$0")" && pwd -P)
3246
- _src_root=""
3247
- for _candidate in "$_script_dir/../../.." "$_script_dir/../.." "$_script_dir/.." "."; do
3248
- if [ -f "$_candidate/shell/release/bundles.json" ] && [ -f "$_candidate/shell/release/profile-release.json" ]; then
3249
- _src_root=$(cd "$_candidate" && pwd -P)
3250
- break
3251
- fi
3252
- done
3253
- [ -n "$_src_root" ] || die "cannot find source tree with bundle and release manifests"
3254
- command -v python3 >/dev/null 2>&1 || die "python3 required for explain-bundles"
3255
- _compiler="$_src_root/hack/compile-shell-profile-release.py"
3256
- [ -f "$_compiler" ] || die "release compiler not found: $_compiler"
3257
- python3 "$_compiler" --root "$_src_root" --explain-bundles
3258
- _rc=$?
3259
- [ "$_rc" -eq 0 ] || die "explain-bundles failed"
3260
- }
3261
-
3262
- cmd_layer_lint() {
3263
- _layer_name="${1:-}"
3264
- [ -n "$_layer_name" ] || die "usage: valise layer-lint <layer-name>"
3265
-
3266
- _script_dir=$(cd "$(path_parent "$0")" && pwd -P)
3267
- _src_root=""
3268
- for _candidate in "$_script_dir/../../.." "$_script_dir/../.." "$_script_dir/.." "."; do
3269
- if [ -d "$_candidate/shell/layers" ]; then
3270
- _src_root=$(cd "$_candidate" && pwd -P)
3271
- break
3272
- fi
3273
- done
3274
- [ -n "$_src_root" ] || die "cannot find source tree with shell/layers/"
3275
-
3276
- _validator="$_src_root/hack/validate-layer.py"
3277
- [ -f "$_validator" ] || die "layer validator not found: $_validator"
3278
-
3279
- command -v python3 >/dev/null 2>&1 || die "python3 required for layer-lint"
3280
- python3 "$_validator" "$_layer_name"
3281
- }
3282
-
3283
- # --- Main dispatch ---
74
+ done
3284
75
 
3285
76
  _cmd="${1:-}"
3286
77
  # POSIX shells may treat a zero-argument shift as a fatal error under -e,
@@ -3292,14 +83,24 @@ fi
3292
83
  case "$_cmd" in
3293
84
  init) cmd_init "$@" ;;
3294
85
  install) cmd_install "$@" ;;
86
+ uninstall) cmd_uninstall "$@" ;;
3295
87
  _verify-release-root) cmd_verify_release_root "$@" ;;
3296
- verify-active) cmd_verify_active "$@" ;;
3297
- doctor) cmd_doctor ;;
3298
- variant) cmd_variant "$@" ;;
88
+ doctor) cmd_doctor "$@" ;;
89
+ release) cmd_release "$@" ;;
3299
90
  make-manifest) cmd_make_manifest "$@" ;;
91
+ registry) cmd_registry "$@" ;;
92
+ new) cmd_new "$@" ;;
93
+ module) cmd_module "$@" ;;
94
+ build) cmd_build "$@" ;;
95
+ apply) cmd_apply "$@" ;;
96
+ status) cmd_status "$@" ;;
97
+ lint) cmd_lint "$@" ;;
98
+ test) cmd_test "$@" ;;
99
+ run) cmd_run "$@" ;;
100
+ env) cmd_env "$@" ;;
3300
101
  compile) cmd_compile "$@" ;;
3301
102
  explain-variant) cmd_explain_variant "$@" ;;
3302
- explain-bundles) cmd_explain_bundles ;;
103
+ explain-bundles) cmd_explain_bundles "$@" ;;
3303
104
  layer-lint) cmd_layer_lint "$@" ;;
3304
105
  version|--version|-v) cmd_version ;;
3305
106
  help|--help|-h|'') usage ;;