@andespindola/crow-term-linux-x64 0.0.0-bootstrap.1 → 0.1.0-alpha.5

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 (33) hide show
  1. package/LICENSE +55 -0
  2. package/NOTICE.md +25 -0
  3. package/README.md +5 -0
  4. package/THIRD_PARTY_LICENSES.txt +71128 -0
  5. package/assets/fonts/OFL.txt +96 -0
  6. package/assets/theme-license.txt +21 -0
  7. package/bin/crow-term +4 -0
  8. package/bin/shell/README.md +37 -0
  9. package/bin/shell/plugins.lock.json +63 -0
  10. package/bin/shell/setup.py +241 -0
  11. package/bin/shell/vendor/fisher/LICENSE.md +7 -0
  12. package/bin/shell/vendor/fisher/completions/fisher.fish +7 -0
  13. package/bin/shell/vendor/fisher/functions/fisher.fish +251 -0
  14. package/bin/shell/vendor/z/LICENSE +21 -0
  15. package/bin/shell/vendor/z/conf.d/z.fish +63 -0
  16. package/bin/shell/vendor/z/functions/__z.fish +178 -0
  17. package/bin/shell/vendor/z/functions/__z_add.fish +49 -0
  18. package/bin/shell/vendor/z/functions/__z_clean.fish +11 -0
  19. package/bin/shell/vendor/z/functions/__z_complete.fish +13 -0
  20. package/bin/shell/vendor/zsh-autosuggestions/LICENSE +23 -0
  21. package/bin/shell/vendor/zsh-autosuggestions/zsh-autosuggestions.zsh +867 -0
  22. package/bin/shell/vendor/zsh-syntax-highlighting/.revision-hash +1 -0
  23. package/bin/shell/vendor/zsh-syntax-highlighting/.version +1 -0
  24. package/bin/shell/vendor/zsh-syntax-highlighting/COPYING.md +23 -0
  25. package/bin/shell/vendor/zsh-syntax-highlighting/highlighters/brackets/brackets-highlighter.zsh +107 -0
  26. package/bin/shell/vendor/zsh-syntax-highlighting/highlighters/cursor/cursor-highlighter.zsh +47 -0
  27. package/bin/shell/vendor/zsh-syntax-highlighting/highlighters/line/line-highlighter.zsh +44 -0
  28. package/bin/shell/vendor/zsh-syntax-highlighting/highlighters/main/main-highlighter.zsh +1853 -0
  29. package/bin/shell/vendor/zsh-syntax-highlighting/highlighters/pattern/pattern-highlighter.zsh +60 -0
  30. package/bin/shell/vendor/zsh-syntax-highlighting/highlighters/regexp/regexp-highlighter.zsh +62 -0
  31. package/bin/shell/vendor/zsh-syntax-highlighting/highlighters/root/root-highlighter.zsh +44 -0
  32. package/bin/shell/vendor/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh +587 -0
  33. package/package.json +35 -1
@@ -0,0 +1,96 @@
1
+ Copyright 2015-2024 Belleve Invis (The Iosevka Project, https://github.com/be5invis/Iosevka)
2
+ Copyright 2026 The Crowquill Mono Project Authors (https://github.com/andersonflima/crowquill-mono)
3
+
4
+ Crowquill Mono is built from a custom build of Iosevka (a "Curly" ss20 variant
5
+ with handwritten forms, a cursive italic and a widened advance). The added
6
+ keyword-bold OpenType feature and the bold keyword glyph variants are original
7
+ to this work.
8
+
9
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
10
+ This license is copied below, and is also available with a FAQ at:
11
+ https://openfontlicense.org
12
+
13
+ -----------------------------------------------------------
14
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
15
+ -----------------------------------------------------------
16
+
17
+ PREAMBLE
18
+ The goals of the Open Font License (OFL) are to stimulate worldwide
19
+ development of collaborative font projects, to support the font creation
20
+ efforts of academic and linguistic communities, and to provide a free and
21
+ open framework in which fonts may be shared and improved in partnership
22
+ with others.
23
+
24
+ The OFL allows the licensed fonts to be used, studied, modified and
25
+ redistributed freely as long as they are not sold by themselves. The
26
+ fonts, including any derivative works, can be bundled, embedded,
27
+ redistributed and/or sold with any software provided that any reserved
28
+ names are not used by derivative works. The fonts and derivatives,
29
+ however, cannot be released under any other type of license. The
30
+ requirement for fonts to remain under this license does not apply to any
31
+ document created using the fonts or their derivatives.
32
+
33
+ DEFINITIONS
34
+ "Font Software" refers to the set of files released by the Copyright
35
+ Holder(s) under this license and clearly marked as such. This may
36
+ include source files, build scripts and documentation.
37
+
38
+ "Reserved Font Name" refers to any names specified as such after the
39
+ copyright statement(s).
40
+
41
+ "Original Version" refers to the collection of Font Software components as
42
+ distributed by the Copyright Holder(s).
43
+
44
+ "Modified Version" refers to any derivative made by adding to, deleting,
45
+ or substituting -- in part or in whole -- any of the components of the
46
+ Original Version, by changing formats or by porting the Font Software to a
47
+ new environment.
48
+
49
+ "Author" refers to any designer, engineer, programmer, technical writer or
50
+ other person who contributed to the Font Software.
51
+
52
+ PERMISSION & CONDITIONS
53
+ Permission is hereby granted, free of charge, to any person obtaining a
54
+ copy of the Font Software, to use, study, copy, merge, embed, modify,
55
+ redistribute, and sell modified and unmodified copies of the Font
56
+ Software, subject to the following conditions:
57
+
58
+ 1) Neither the Font Software nor any of its individual components, in
59
+ Original or Modified Versions, may be sold by itself.
60
+
61
+ 2) Original or Modified Versions of the Font Software may be bundled,
62
+ redistributed and/or sold with any software, provided that each copy
63
+ contains the above copyright notice and this license. These can be
64
+ included either as stand-alone text files, human-readable headers or in
65
+ the appropriate machine-readable metadata fields within text or binary
66
+ files as long as those fields can be easily viewed by the user.
67
+
68
+ 3) No Modified Version of the Font Software may use the Reserved Font
69
+ Name(s) unless explicit written permission is granted by the corresponding
70
+ Copyright Holder. This restriction only applies to the primary font name as
71
+ presented to the users.
72
+
73
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
74
+ Software shall not be used to promote, endorse or advertise any Modified
75
+ Version, except to acknowledge the contribution(s) of the Copyright
76
+ Holder(s) and the Author(s) or with their explicit written permission.
77
+
78
+ 5) The Font Software, modified or unmodified, in part or in whole, must be
79
+ distributed entirely under this license, and must not be distributed under
80
+ any other license. The requirement for fonts to remain under this license
81
+ does not apply to any document created using the Font Software.
82
+
83
+ TERMINATION
84
+ This license becomes null and void if any of the above conditions are not
85
+ met.
86
+
87
+ DISCLAIMER
88
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
89
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
90
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
91
+ COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
92
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
93
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
94
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
95
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
96
+ DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anderson Faustino Lima
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/bin/crow-term ADDED
@@ -0,0 +1,4 @@
1
+ [diffend] Oversized file quarantined before diffing.
2
+ name: package/bin/crow-term
3
+ size: 52400512 bytes
4
+ sha256: f1e33b5367d676b4d9f9a35a68de5f73a736924cd2488613262feb44043c844d
@@ -0,0 +1,37 @@
1
+ # Reproducible, opt-in shell profiles
2
+
3
+ Run `python3 shell/setup.py --help`. Requires Python 3.9+ on Unix/macOS/WSL.
4
+ Profiles are separate from personal startup files; installation and launching
5
+ are two explicit operations. Nothing calls `chsh`, a package manager, `curl|sh`,
6
+ `git clone`, Fisher, or a plugin's installer.
7
+
8
+ `vendor/` contains only the runtime source files and required license notices
9
+ listed in `plugins.lock.json`. The lock records official repository URLs,
10
+ immutable upstream commits, upstream archive SHA256 and every copied file's
11
+ SHA256. Files are unmodified, except that unrelated upstream files are omitted.
12
+ Setup verifies each selected vendored file before writing any target. No network
13
+ is used by setup, dry-run, or tests.
14
+
15
+ | Plugin | Upstream commit | License notice |
16
+ | --- | --- | --- |
17
+ | [Fisher](https://github.com/jorgebucaran/fisher) | `791da644d33d392216f6b1a9b5fc1e470db6d7f2` | `vendor/fisher/LICENSE.md` (MIT) |
18
+ | [fish z](https://github.com/jethrokuan/z) | `26a50962bc68f5cb60fc488ee008b3d4d5be75f4` | `vendor/z/LICENSE` (MIT) |
19
+ | [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions) | `85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5` | `vendor/zsh-autosuggestions/LICENSE` (MIT) |
20
+ | [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting) | `e6683f20e5c38d3e5447f45845d04ddda75d0f23` | `vendor/zsh-syntax-highlighting/COPYING.md` (BSD-3-Clause) |
21
+
22
+ These exact official archives were downloaded and hashed on 2026-10-28. This
23
+ is a reproducibility pin, not a promise that upstream code is vulnerability-free.
24
+ To update: review upstream changes and licenses, fetch a chosen immutable commit
25
+ from its official repository, replace only this allowlist and regenerate/review
26
+ the SHA256 entries together. Changing a digest alone to suppress an unexplained
27
+ mismatch is not a valid update. Profiles installed by an older lock are never
28
+ overwritten: choose a new versioned prefix or back up and manage them explicitly.
29
+
30
+ The fuller source setup declared Fisher, z, Shellder, Tide v5 and Catppuccin fish,
31
+ while invoking Starship. Crow Term intentionally chooses only Fisher + z, native
32
+ fish editing/completions and one small built-in monochrome prompt. It does not
33
+ stack competing prompt engines. The zsh choice is a new minimal portable profile,
34
+ not a claim that these plugins were discovered in the owner's `.zshrc`.
35
+
36
+ See [shell integration](../docs/shell-integration.md) for launch semantics,
37
+ platform limits and the boundary between a terminal and a shell.
@@ -0,0 +1,63 @@
1
+ {
2
+ "schema": 1,
3
+ "plugins": [
4
+ {
5
+ "name": "fisher",
6
+ "repository": "https://github.com/jorgebucaran/fisher",
7
+ "commit": "791da644d33d392216f6b1a9b5fc1e470db6d7f2",
8
+ "archive_url": "https://codeload.github.com/jorgebucaran/fisher/tar.gz/791da644d33d392216f6b1a9b5fc1e470db6d7f2",
9
+ "archive_sha256": "3450711cf552c2032e93e775c3cebb082c0a321ee1dd046d2d41cbc7b77d707f",
10
+ "files": {
11
+ "LICENSE.md": "f101c761d255d0dddc77dd8a9327733b03d381798ec54a1bb718367207b48a8e",
12
+ "functions/fisher.fish": "0fb6c81ae3003e95b5671766fa6c25c3597066e29965b7772f6c1b007387356d",
13
+ "completions/fisher.fish": "6ef51da07e11ed534ce828770dfa3135551bafe9aa3c28700cee1fc5f053cd48"
14
+ }
15
+ },
16
+ {
17
+ "name": "z",
18
+ "repository": "https://github.com/jethrokuan/z",
19
+ "commit": "26a50962bc68f5cb60fc488ee008b3d4d5be75f4",
20
+ "archive_url": "https://codeload.github.com/jethrokuan/z/tar.gz/26a50962bc68f5cb60fc488ee008b3d4d5be75f4",
21
+ "archive_sha256": "58bbb82d1b5e8e9a5f4a9d793115c99d20a183bb1dfbd5d4e2285f8c5579582d",
22
+ "files": {
23
+ "LICENSE": "6768e40ee8241d60df364bcf60a1d2dba0dfa7ecb699a658c186c4ef98157e02",
24
+ "conf.d/z.fish": "8d8499125844a249b29a5a312182373ac268bfafe9c1468c764edde6081b7f62",
25
+ "functions/__z.fish": "f379818b6ec429db4f8fe1d4cf0baeb57fc9dabbd8603fb219b21b1164c7d6e0",
26
+ "functions/__z_add.fish": "98c54603a89ff2f4c9262a127a66b072f22e6ad752dd2ad97adb17b4f98da1dc",
27
+ "functions/__z_clean.fish": "dafc74f9cd1f9607c0ece6727402ea7ac3e7bf4554626fe9eb237e1b07440215",
28
+ "functions/__z_complete.fish": "73a08d410621594a0730128d9c997e5fb0008f278c9c42ff156a460014a42328"
29
+ }
30
+ },
31
+ {
32
+ "name": "zsh-autosuggestions",
33
+ "repository": "https://github.com/zsh-users/zsh-autosuggestions",
34
+ "commit": "85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5",
35
+ "archive_url": "https://codeload.github.com/zsh-users/zsh-autosuggestions/tar.gz/85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5",
36
+ "archive_sha256": "20665e469e720e674964a66854d5534b9af78cdfd438512746ecd1ade8e819ce",
37
+ "files": {
38
+ "LICENSE": "4598a6be0b8d7f2b708da5259d2a30d4e15e59b3c66781bab9e27744a9f859d8",
39
+ "zsh-autosuggestions.zsh": "eec7ba8f7a71414ace0ea0fab0908d005b24cf65d83b169c0ff97815d3cfc51a"
40
+ }
41
+ },
42
+ {
43
+ "name": "zsh-syntax-highlighting",
44
+ "repository": "https://github.com/zsh-users/zsh-syntax-highlighting",
45
+ "commit": "e6683f20e5c38d3e5447f45845d04ddda75d0f23",
46
+ "archive_url": "https://codeload.github.com/zsh-users/zsh-syntax-highlighting/tar.gz/e6683f20e5c38d3e5447f45845d04ddda75d0f23",
47
+ "archive_sha256": "6e8258a74e6f3cac03e1bb5ee72504bc4d819904e9aa742d62f60833168db265",
48
+ "files": {
49
+ "COPYING.md": "d810908db3cb75d30e46f5e55b18c8f483e1bc625b8f7dc5a581f5ad353af82e",
50
+ ".version": "97fd9d491486c9c26ce918b0ad429584dddd807f34655f2342872d8175383094",
51
+ ".revision-hash": "0e4e0c3aaec5a3efe933c7b41cb940fe5e6c28874f5075a9f68427f63135abde",
52
+ "zsh-syntax-highlighting.zsh": "156ebe9530eb991dcef54d476967e2ff4338d35dabaaff9e5462673a287cc63b",
53
+ "highlighters/brackets/brackets-highlighter.zsh": "b3ac4a66edf133b8f029332e787b7d36e2e1d7cabec0d271f7e5fe6724490dd3",
54
+ "highlighters/cursor/cursor-highlighter.zsh": "bd6ef3aae900fee57ff132360b3dd9d68df5aab150a33e32259fd5adbe8efd49",
55
+ "highlighters/line/line-highlighter.zsh": "1a12c094770bc00276395dc71a398a63fd768c433453d35f4e47e5d315dfacf0",
56
+ "highlighters/main/main-highlighter.zsh": "1f59176bc1e5fd8ac8eaa85dd7a4cd2a95083ee7c689a430ff4a5e2e9eee0061",
57
+ "highlighters/pattern/pattern-highlighter.zsh": "c2d5b50db13936421672b5ce16c0d7ec4f1abfeded34ea3a23bb39d2499b953b",
58
+ "highlighters/regexp/regexp-highlighter.zsh": "f567458da4fb89cae8ea220b8febea11ed67ab6f6c8f5e0d6723ea7285e932e7",
59
+ "highlighters/root/root-highlighter.zsh": "7a038444d4cd60f9eaf07993b6a14d0055ad8706e09a32780cb65ea0a90530ee"
60
+ }
61
+ }
62
+ ]
63
+ }
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env python3
2
+ """Create an opt-in Crow Term shell profile; never edit a personal dotfile.
3
+
4
+ Only Python's standard library is required. Plugin installation is offline and
5
+ copies an allowlist of vendored, pinned, SHA256-verified upstream files.
6
+ """
7
+ import argparse
8
+ import hashlib
9
+ import json
10
+ import os
11
+ from pathlib import Path, PurePosixPath
12
+ import stat
13
+ import sys
14
+ import tempfile
15
+
16
+ HERE = Path(__file__).resolve().parent
17
+
18
+
19
+ def quote_fish(value):
20
+ return "'" + str(value).replace("\\", "\\\\").replace("'", "\\'") + "'"
21
+
22
+
23
+ def quote_zsh(value):
24
+ return "'" + str(value).replace("'", "'\\''") + "'"
25
+
26
+
27
+ def checked_prefix(value):
28
+ path = Path(os.path.abspath(os.path.expanduser(value)))
29
+ if any(ord(c) < 32 or ord(c) == 127 for c in str(path)):
30
+ raise ValueError("prefix must not contain control characters")
31
+ if path.is_symlink():
32
+ raise ValueError("prefix must not be a symlink")
33
+ path = path.resolve()
34
+ if path in (Path(path.anchor), Path.home().resolve()):
35
+ raise ValueError("choose a dedicated profile directory, not root or HOME")
36
+ if path.exists() and not path.is_dir():
37
+ raise ValueError("prefix is not a directory")
38
+ return path
39
+
40
+
41
+ def fish_profile(prefix):
42
+ q = quote_fish
43
+ return f"""# Crow Term isolated profile. Generated; no personal dotfiles are sourced.
44
+ set -g fisher_path {q(prefix / 'fish-managed')}
45
+ set -g fish_function_path {q(prefix / 'fish-managed/functions')} {q(prefix / 'plugins/fisher/functions')} {q(prefix / 'plugins/z/functions')} $fish_function_path
46
+ set -g fish_complete_path {q(prefix / 'plugins/fisher/completions')} $fish_complete_path
47
+ set -gx Z_DATA_DIR {q(prefix / 'data/z')}
48
+ set -gx Z_DATA {q(prefix / 'data/z/data')}
49
+ if test -f {q(prefix / 'plugins/z/conf.d/z.fish')}
50
+ source {q(prefix / 'plugins/z/conf.d/z.fish')}
51
+ end
52
+ set -g fish_color_command normal --bold
53
+ set -g fish_color_keyword normal --bold
54
+ set -g fish_color_quote 606060
55
+ set -g fish_color_comment 6A6A6A --italics
56
+ set -g fish_color_param normal
57
+ set -g fish_color_operator normal
58
+ set -g fish_color_redirection normal
59
+ set -g fish_color_end normal
60
+ set -g fish_color_error normal --bold
61
+ set -g fish_color_autosuggestion 808080
62
+ set -g fish_color_selection --reverse
63
+ set -g fish_color_search_match --reverse
64
+ function fish_prompt
65
+ set -l last_status $status
66
+ set_color normal
67
+ printf '%s' (prompt_pwd)
68
+ if test $last_status -ne 0
69
+ printf ' [%s]' $last_status
70
+ end
71
+ printf ' > '
72
+ set_color normal
73
+ end
74
+ """
75
+
76
+
77
+ def zsh_profile(prefix):
78
+ q = quote_zsh
79
+ return f"""# Crow Term isolated profile; no personal dotfiles or framework.
80
+ HISTFILE={q(prefix / 'data/zsh-history')}
81
+ HISTSIZE=10000
82
+ SAVEHIST=10000
83
+ setopt HIST_IGNORE_SPACE
84
+ PROMPT='%f%~ > '
85
+ ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=#808080'
86
+ if [[ -f {q(prefix / 'plugins/zsh-autosuggestions/zsh-autosuggestions.zsh')} ]]; then
87
+ source {q(prefix / 'plugins/zsh-autosuggestions/zsh-autosuggestions.zsh')}
88
+ fi
89
+ typeset -gA ZSH_HIGHLIGHT_STYLES
90
+ ZSH_HIGHLIGHT_STYLES[command]='bold'
91
+ ZSH_HIGHLIGHT_STYLES[builtin]='bold'
92
+ ZSH_HIGHLIGHT_STYLES[reserved-word]='bold'
93
+ ZSH_HIGHLIGHT_STYLES[comment]='fg=#6A6A6A,italic'
94
+ ZSH_HIGHLIGHT_STYLES[single-quoted-argument]='fg=#606060'
95
+ ZSH_HIGHLIGHT_STYLES[double-quoted-argument]='fg=#606060'
96
+ # Must remain the final sourced plugin (upstream requirement).
97
+ if [[ -f {q(prefix / 'plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh')} ]]; then
98
+ source {q(prefix / 'plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh')}
99
+ fi
100
+ """
101
+
102
+
103
+ def launcher(prefix, shell):
104
+ # Embed data as Python literals, not shell substitutions. execvpe receives an
105
+ # argument array, and profile path quoting is only for fish's -C expression.
106
+ args = (["--no-config", "--init-command", "source " + quote_fish(prefix / "fish/config.fish")]
107
+ if shell == "fish" else ["-d", "-i"])
108
+ return f"""#!/usr/bin/env python3
109
+ import os
110
+ from pathlib import Path
111
+ import shutil
112
+ import sys
113
+ prefix = Path({str(prefix)!r})
114
+ env = os.environ.copy()
115
+ # Isolate shell universal variables, history, plugin state and completion cache.
116
+ # Child applications inherit these XDG directories too; this is opt-in.
117
+ for key, rel in {{'XDG_CONFIG_HOME': 'config', 'XDG_DATA_HOME': 'data', 'XDG_CACHE_HOME': 'cache', 'XDG_STATE_HOME': 'state'}}.items():
118
+ folder = prefix / rel
119
+ folder.mkdir(mode=0o700, parents=True, exist_ok=True)
120
+ env[key] = str(folder)
121
+ env['ZDOTDIR'] = str(prefix / 'zsh')
122
+ program = shutil.which({shell!r})
123
+ if not program:
124
+ sys.exit('Required shell not found on PATH: {shell}')
125
+ os.execvpe(program, [program] + {args!r} + sys.argv[1:], env)
126
+ """
127
+
128
+
129
+ def plan_files(prefix, shell, install_plugins=False):
130
+ profile = ("fish/config.fish", fish_profile(prefix)) if shell == "fish" else ("zsh/.zshrc", zsh_profile(prefix))
131
+ plan = {profile[0]: (profile[1].encode(), 0o600),
132
+ f"launch-{shell}.py": (launcher(prefix, shell).encode(), 0o700)}
133
+ lock_data = (HERE / "plugins.lock.json").read_bytes()
134
+ lock = json.loads(lock_data)
135
+ if lock.get("schema") != 1:
136
+ raise ValueError("unsupported plugin lock schema")
137
+ if install_plugins:
138
+ selected = {"fisher", "z"} if shell == "fish" else {"zsh-autosuggestions", "zsh-syntax-highlighting"}
139
+ for plugin in lock["plugins"]:
140
+ if plugin["name"] not in selected:
141
+ continue
142
+ for rel, digest in plugin["files"].items():
143
+ path = PurePosixPath(rel)
144
+ if path.is_absolute() or ".." in path.parts:
145
+ raise ValueError("invalid path in plugin lock")
146
+ source = HERE / "vendor" / plugin["name"] / rel
147
+ if source.is_symlink() or not source.is_file():
148
+ raise ValueError(f"missing/nonregular vendored file: {source}")
149
+ content = source.read_bytes()
150
+ if hashlib.sha256(content).hexdigest() != digest:
151
+ raise ValueError(f"SHA256 mismatch: {source}")
152
+ plan[f"plugins/{plugin['name']}/{rel}"] = (content, 0o600)
153
+ plan["plugins.lock.json"] = (lock_data, 0o600)
154
+ if shell == "fish":
155
+ pins = [p['repository'].removeprefix('https://github.com/') + '@' + p['commit']
156
+ for p in lock['plugins'] if p['name'] in selected]
157
+ plan["fish-managed/fish_plugins"] = (("\n".join(pins) + "\n").encode(), 0o600)
158
+ return plan
159
+
160
+
161
+ def check_destination(prefix, rel, data):
162
+ dest = prefix / rel
163
+ for current in [prefix] + list(dest.relative_to(prefix).parents)[::-1]:
164
+ # Relative parents are handled below; only inspect paths beneath prefix.
165
+ if not current.is_absolute():
166
+ current = prefix / current
167
+ if current.is_symlink():
168
+ raise ValueError(f"refusing symlink directory: {current}")
169
+ if current.exists() and not current.is_dir():
170
+ raise ValueError(f"not a directory: {current}")
171
+ if dest.is_symlink():
172
+ raise ValueError(f"refusing symlink file: {dest}")
173
+ if dest.exists():
174
+ if not stat.S_ISREG(dest.stat().st_mode) or dest.read_bytes() != data:
175
+ raise ValueError(f"existing file differs; refusing overwrite: {dest}")
176
+ return False
177
+ return True
178
+
179
+
180
+ def create_directory(path):
181
+ missing = []
182
+ while not path.exists():
183
+ missing.append(path)
184
+ path = path.parent
185
+ if path.is_symlink() or not path.is_dir():
186
+ raise ValueError(f"unsafe directory: {path}")
187
+ for directory in reversed(missing):
188
+ directory.mkdir(mode=0o700)
189
+
190
+
191
+ def write_new(prefix, rel, data, mode):
192
+ if not check_destination(prefix, rel, data):
193
+ return
194
+ dest = prefix / rel
195
+ create_directory(dest.parent)
196
+ temporary = None
197
+ try:
198
+ with tempfile.NamedTemporaryFile(dir=dest.parent, prefix=".crow-term-", delete=False) as file:
199
+ temporary = Path(file.name)
200
+ os.fchmod(file.fileno(), mode)
201
+ file.write(data)
202
+ file.flush()
203
+ os.fsync(file.fileno())
204
+ # Atomic no-clobber publish. Unlike replace()/rename(), link() cannot
205
+ # overwrite an existing destination, even if another setup races us.
206
+ try:
207
+ os.link(temporary, dest)
208
+ except FileExistsError:
209
+ if check_destination(prefix, rel, data):
210
+ raise
211
+ finally:
212
+ if temporary is not None:
213
+ temporary.unlink(missing_ok=True)
214
+
215
+
216
+ def main(argv=None):
217
+ parser = argparse.ArgumentParser(description=__doc__)
218
+ parser.add_argument("--shell", required=True, choices=("fish", "zsh"))
219
+ parser.add_argument("--prefix", required=True, help="dedicated Crow Term profile directory")
220
+ parser.add_argument("--install-plugins", action="store_true", help="copy verified vendored plugins (offline)")
221
+ parser.add_argument("--dry-run", action="store_true", help="validate and print plan without writing")
222
+ args = parser.parse_args(argv)
223
+ try:
224
+ prefix = checked_prefix(args.prefix)
225
+ plan = plan_files(prefix, args.shell, args.install_plugins)
226
+ # Preflight every target before the first write. Interrupted execution
227
+ # may leave a partial set of complete files; rerun safely resumes it.
228
+ changes = {rel: check_destination(prefix, rel, data) for rel, (data, _) in plan.items()}
229
+ for rel, (data, mode) in plan.items():
230
+ print(("create " if changes[rel] else "keep ") + str(prefix / rel))
231
+ if not args.dry_run:
232
+ write_new(prefix, rel, data, mode)
233
+ print(("Would launch: " if args.dry_run else "Launch explicitly: ") + f"python3 {str(prefix / ('launch-' + args.shell + '.py'))!r}")
234
+ return 0
235
+ except (OSError, ValueError, KeyError, TypeError) as error:
236
+ print(f"shell setup: {error}", file=sys.stderr)
237
+ return 1
238
+
239
+
240
+ if __name__ == "__main__":
241
+ sys.exit(main())
@@ -0,0 +1,7 @@
1
+ Copyright © Jorge Bucaran <<https://jorgebucaran.com>>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,7 @@
1
+ complete --command fisher --exclusive --long help --description "Print help"
2
+ complete --command fisher --exclusive --long version --description "Print version"
3
+ complete --command fisher --exclusive --condition __fish_use_subcommand --arguments install --description "Install plugins"
4
+ complete --command fisher --exclusive --condition __fish_use_subcommand --arguments update --description "Update installed plugins"
5
+ complete --command fisher --exclusive --condition __fish_use_subcommand --arguments remove --description "Remove installed plugins"
6
+ complete --command fisher --exclusive --condition __fish_use_subcommand --arguments list --description "List installed plugins matching regex"
7
+ complete --command fisher --exclusive --condition "__fish_seen_subcommand_from update remove" --arguments "(fisher list)"