You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+10-1Lines changed: 10 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,12 +4,13 @@
4
4
5
5
`shll` is a meta-CLI for the sahil87 toolkit. It composes operations that span every per-tool CLI (`hop`, `wt`, `fab-kit`, `rk`, `tu`, `idea`) so you have one entry point for cross-toolkit concerns.
6
6
7
-
Three subcommands today:
7
+
Four subcommands today:
8
8
9
9
| Command | Purpose |
10
10
|---------|---------|
11
11
|`shll update`|`brew update` then `brew upgrade` for every installed sahil87 tool |
12
12
|`shll shell-init <shell>`| Single eval-safe shell-init blob composed from all installed sahil87 tools that expose one |
13
+
|`shll shell-install [shell]`| Append the `shll shell-init` eval line to your shell rc file (idempotent; supports `--print` and `--uninstall`) |
13
14
|`shll version`| Versions of `shll` itself plus every installed sahil87 tool, plain text, paste-friendly for bug reports |
14
15
15
16
Per-tool CLIs continue to work standalone — `shll` wraps them, it does not replace them.
@@ -28,6 +29,14 @@ brew install sahil87/tap/shll
28
29
brew install sahil87/tap/all # installs every sahil87 tool, including shll
29
30
```
30
31
32
+
Then wire shell integration into your rc file with one command:
33
+
34
+
```sh
35
+
shll shell-install # auto-detect shell, append eval line to your rc file
36
+
```
37
+
38
+
`shll shell-install` is idempotent — re-running is a no-op when the line is already present. It preserves dotfile-manager symlinks (chezmoi, dotbot, stow, yadm). Supports `--print` (dry-run) and `--uninstall` (clean removal). If you'd rather edit the rc file by hand, the manual fallback is below under [Single-line shell integration](#single-line-shell-integration).
Copy file name to clipboardExpand all lines: docs/memory/cli/commands.md
+10-8Lines changed: 10 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# cli/commands
2
2
3
-
Top-level command surface for the `shll` binary — the cobra root, the three subcommands it wires up, the exit-code translation layer, and the hardcoded tool roster every subcommand consumes.
3
+
Top-level command surface for the `shll` binary — the cobra root, the four subcommands it wires up, the exit-code translation layer, and the hardcoded tool roster every subcommand consumes.
4
4
5
5
## Binary entry point
6
6
@@ -15,34 +15,35 @@ Top-level command surface for the `shll` binary — the cobra root, the three su
15
15
16
16
-`Use: "shll"`
17
17
-`Short: "meta-CLI for the sahil87 toolkit"`
18
-
- A `Long` block listing the three subcommands and noting that per-tool CLIs continue to work standalone.
18
+
- A `Long` block listing the four subcommands and noting that per-tool CLIs continue to work standalone.
19
19
-`SilenceUsage: true` and `SilenceErrors: true` — usage is not printed on RunE errors, and cobra's default error printer is suppressed. The `translateExit` layer in `main.go` owns stderr.
20
-
-`AddCommand` for `newUpdateCmd()`, `newShellInitCmd()`, `newVersionCmd()`.
20
+
-`AddCommand` for `newUpdateCmd()`, `newShellInitCmd()`, `newShellInstallCmd()`, `newVersionCmd()`.
21
21
22
-
Per Constitution VII (Minimal Surface Area), the v0.1.0 surface is exactly these three subcommands. Adding a new top-level subcommand requires explicit justification in the change's intake.
22
+
Per Constitution VII (Minimal Surface Area), the v0.1.0 surface is exactly these four subcommands. Adding a new top-level subcommand requires explicit justification in the change's intake.
23
23
24
24
### Constitution VII justification per subcommand
25
25
26
-
These were locked in at spec time (Design Decision #1) and are reproduced here:
26
+
These are locked in at spec time and are reproduced here:
27
27
28
28
-**`update`** — solves the no-single-update-command pain (`brew upgrade sahil87/tap/all` does NOT propagate to deps). Cannot be a flag on an existing tool because the entry point itself is what's missing.
29
29
-**`shell-init`** — solves the cold-start cost and N-eval-line burden when multiple shell-integrating tools are installed. Per-tool `shell-init` keeps working standalone (Constitution IV).
30
+
-**`shell-install`** — solves the manual-rc-edit cliff in the post-`brew install` onboarding flow. Cannot be a flag on `shell-init` (it *invokes*`shell-init`, so making it a sub-flag is structurally self-referential). Cannot live in a per-tool CLI (per-tool CLIs emit their own shell-init; this command writes the cross-tool composition `eval "$(shll shell-init <shell>)"`, which is exactly what shll exists for).
30
31
-**`version`** — solves the bug-report triage pain. Cannot live on a per-tool CLI because the value is the cross-tool aggregation.
31
32
32
33
## Exit-code translation
33
34
34
35
`translateExit(err error) int` in `src/cmd/shll/main.go:38` is the single mapping from `RunE` errors to OS exit codes. It uses two error sentinels defined in `src/cmd/shll/main.go`:
35
36
36
37
-`errSilent = errors.New("shll: silent error")` (`src/cmd/shll/main.go:58`) — returned by subcommands that have already written their own diagnostic to stderr. Maps to exit code 1; `translateExit` does not write anything else.
37
-
-`errExitCode{code, msg}` (`src/cmd/shll/main.go:63`) — used when a subcommand needs an exit code other than 0 or 1. Today only `shll shell-init`uses this, exiting 2 on bad/missing shell argument. If `msg` is non-empty, `translateExit` writes it to stderr.
38
+
-`errExitCode{code, msg}` (`src/cmd/shll/main.go:63`) — used when a subcommand needs an exit code other than 0 or 1. Today `shll shell-init`and `shll shell-install` use this, exiting 2 on bad/missing shell argument and on related user-invocation errors (missing rc file, mutually-exclusive flags). If `msg` is non-empty, `translateExit` writes it to stderr.
38
39
39
40
Default fallback: any other error is printed to stderr and exits 1.
40
41
41
42
This layered design keeps cobra's own error printing out of the way (`SilenceErrors: true`) and concentrates exit-code policy in one place. The hop binary uses the same pattern; shll mirrors it.
42
43
43
44
## Subcommand factory pattern
44
45
45
-
Every subcommand follows `newXxxCmd()` returning `*cobra.Command` (no globals, no init() side effects). The cobra command's `RunE` calls a thin top-level helper (`runUpdate`, `runShellInit`, `runVersion`) that takes explicit `io.Writer` arguments — this is the test seam: tests drive these directly with `bytes.Buffer` writers and a fake `proc.Runner`.
46
+
Every subcommand follows `newXxxCmd()` returning `*cobra.Command` (no globals, no init() side effects). The cobra command's `RunE` calls a thin top-level helper (`runUpdate`, `runShellInit`, `runShellInstall`, `runVersion`) that takes explicit `io.Writer` arguments — this is the test seam: tests drive these directly with `bytes.Buffer` writers and a fake `proc.Runner` (or, for `shell-install`, no fake — the command does file I/O only).
46
47
47
48
## Hardcoded tool roster
48
49
@@ -76,6 +77,7 @@ Roster invariants:
76
77
|`brew.go`| Shared brew helpers used by every subcommand: `hasBrew`, `isInstalled`, `brewBinary`, `brewMissingHint`. See [update](update.md) for details. |
77
78
|`update.go`|`newUpdateCmd()` + `runUpdate`. See [update](update.md). |
78
79
|`shell_init.go`|`newShellInitCmd()` + `runShellInit`. See [shell-init](shell-init.md). |
80
+
|`shell_install.go`|`newShellInstallCmd()` + `runShellInstall`. See [shell-install](shell-install.md). |
79
81
|`version.go`|`newVersionCmd()` + `runVersion`. See [version](version.md). |
80
82
81
83
Each command file has a paired `_test.go` (test-alongside per `code-quality.md`).
@@ -85,4 +87,4 @@ Each command file has a paired `_test.go` (test-alongside per `code-quality.md`)
85
87
- Constitution I (Security First) → all subprocesses go through [`internal/proc`](../internal/proc.md).
86
88
- Constitution III (Wrap, Don't Reinvent) + IV (Composition, Not Replacement) → every subcommand shells out; nothing reimplements brew or per-tool logic.
87
89
- Constitution V (Graceful Degradation) → uninstalled tools never produce errors; missing tools are skipped silently.
88
-
- Constitution VII (Minimal Surface Area) → subcommand list is closed at three for v0.1.0.
90
+
- Constitution VII (Minimal Surface Area) → subcommand list is closed at four for v0.1.0 (`update`, `shell-init`, `shell-install`, `version`).
- Rc-file installer: [cli/shell-install](shell-install.md) — wraps `shll shell-init <shell>` in an `eval` line and writes it to the user's rc file (idempotent install / `--print` dry-run / `--uninstall` removal).
102
103
- Constitution V (Graceful Degradation) — uninstalled tools omitted silently.
0 commit comments