amont 1.25.1 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -266
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -29,89 +29,28 @@ How that stacks up against pre-commit, lefthook and husky, feature by feature:
|
|
|
29
29
|
|
|
30
30
|
## Install
|
|
31
31
|
|
|
32
|
-
**Linux and macOS**
|
|
33
|
-
|
|
34
32
|
```sh
|
|
33
|
+
# Linux and macOS
|
|
35
34
|
curl -fsSL https://raw.githubusercontent.com/fredericrous/amont/main/install/install.sh | sh
|
|
36
35
|
```
|
|
37
36
|
|
|
38
|
-
**Windows** (PowerShell — the line above is POSIX `sh` and only reaches
|
|
39
|
-
Windows through Git Bash)
|
|
40
|
-
|
|
41
37
|
```powershell
|
|
38
|
+
# Windows (the line above is POSIX sh and only reaches Windows through Git Bash)
|
|
42
39
|
irm https://raw.githubusercontent.com/fredericrous/amont/main/install/install.ps1 | iex
|
|
43
40
|
```
|
|
44
41
|
|
|
45
42
|
Either one downloads a release binary, verifies it against the published
|
|
46
|
-
`SHA256SUMS`, and puts it where the hooks already look
|
|
47
|
-
|
|
48
|
-
repository, by you, afterwards.
|
|
43
|
+
`SHA256SUMS`, and puts it where the hooks already look. Both **enable
|
|
44
|
+
nothing** — hooks are turned on per repository, by you, afterwards:
|
|
49
45
|
|
|
50
46
|
```sh
|
|
51
47
|
cd <your-repo> && amont install # this repository only
|
|
52
48
|
amont list # what would run here, and why not
|
|
53
49
|
```
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
silicon) and Windows. Or build from source: `cargo build --release`.
|
|
59
|
-
|
|
60
|
-
From [crates.io](https://crates.io/crates/amont):
|
|
61
|
-
|
|
62
|
-
```sh
|
|
63
|
-
cargo install amont
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
Or with Homebrew:
|
|
67
|
-
|
|
68
|
-
```sh
|
|
69
|
-
brew tap fredericrous/tap
|
|
70
|
-
brew trust fredericrous/tap # Homebrew asks this of every third-party tap
|
|
71
|
-
brew install amont
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
**In a JavaScript project**, the binary can travel with the repository rather
|
|
75
|
-
than with the machine, so a teammate who clones it needs no install step at all:
|
|
76
|
-
|
|
77
|
-
```sh
|
|
78
|
-
npm i -D amont # or: pnpm add -D amont
|
|
79
|
-
npm pkg set scripts.prepare="amont init"
|
|
80
|
-
npm install # the hooks appear
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Six prebuilt platform packages are declared as `optionalDependencies`, so npm
|
|
84
|
-
installs exactly one and runs no install scripts at all — this survives
|
|
85
|
-
`npm ci --ignore-scripts`. `amont init` wires up that one repository and
|
|
86
|
-
nothing else: no `~/.local/bin`, no template directory, no prompts.
|
|
87
|
-
|
|
88
|
-
If the project also installs **without** its dev dependencies anywhere — `npm ci
|
|
89
|
-
--omit=dev`, the usual second stage of a Dockerfile — write
|
|
90
|
-
`"prepare": "amont init || true"` there, since `prepare` still runs and `amont`
|
|
91
|
-
will not be installed. [The details](docs/install.md#if-anything-ever-installs-without-your-dev-dependencies).
|
|
92
|
-
|
|
93
|
-
## Uninstall
|
|
94
|
-
|
|
95
|
-
```sh
|
|
96
|
-
amont uninstall # this repository
|
|
97
|
-
amont uninstall --binary # …and remove ~/.local/bin/amont too
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
Uninstall is listed second on purpose. These hooks can block a commit, so the
|
|
101
|
-
honest question to answer first is how you get out — and the answer is that
|
|
102
|
-
`uninstall` removes our five shims and **nothing else**. A hook you wrote
|
|
103
|
-
yourself is left where it is and named in the output, whatever it is; a hook it
|
|
104
|
-
cannot even read is named too rather than passed over in silence. Your
|
|
105
|
-
`hook.skip` and `amont.severity` settings are never touched, because those
|
|
106
|
-
are your statements about your repository.
|
|
107
|
-
|
|
108
|
-
This is also why the README does not tell you to run
|
|
109
|
-
`rm $(git rev-parse --git-dir)/hooks/*`. That glob deletes every hook in the
|
|
110
|
-
directory — including ones other tools installed and ones you wrote — to remove
|
|
111
|
-
five files that belong to us.
|
|
112
|
-
|
|
113
|
-
To bypass a single run rather than uninstall: `git commit --no-verify`.
|
|
114
|
-
To turn off one check permanently, see [Turning a check off, or down](#turning-a-check-off-or-down).
|
|
51
|
+
Homebrew, crates.io, npm, prebuilt binaries for six targets, building from
|
|
52
|
+
source, and what `--force` will and will not do:
|
|
53
|
+
[installing and activating](docs/install.md).
|
|
115
54
|
|
|
116
55
|
## What actually runs
|
|
117
56
|
|
|
@@ -136,210 +75,155 @@ pre-push
|
|
|
136
75
|
● runs here ○ inert ⊘ skipped via hook.skip ✗ declaration unusable
|
|
137
76
|
```
|
|
138
77
|
|
|
139
|
-
Thirty-seven built-in checks across five git hooks, plus any your repository
|
|
140
|
-
itself.
|
|
78
|
+
Thirty-seven built-in checks across five git hooks, plus any your repository
|
|
79
|
+
declares itself. What each one needs before it fires:
|
|
141
80
|
[the checks reference](docs/checks.md).
|
|
142
81
|
|
|
143
|
-
##
|
|
82
|
+
## Turning hooks on
|
|
144
83
|
|
|
145
|
-
**Per repository**
|
|
84
|
+
**Per repository** is the default, and nothing runs anywhere you did not ask:
|
|
146
85
|
|
|
147
86
|
```sh
|
|
148
87
|
cd <your-repo> && amont install
|
|
149
88
|
amont-fleet install --root ~/Developer # or in bulk, across many repos
|
|
150
89
|
```
|
|
151
90
|
|
|
152
|
-
|
|
153
|
-
refuse — one carrying no marker of ours, or a symlink. Even `--force` never
|
|
154
|
-
writes a tracked file or a directory. The full semantics:
|
|
155
|
-
[what `--force` will and will not do](docs/install.md#--force-and-what-it-will-not-do).
|
|
156
|
-
|
|
157
|
-
**Everywhere, forever** — an opt-in, and a real one:
|
|
91
|
+
**Everywhere, forever** is an opt-in, and a real one:
|
|
158
92
|
|
|
159
93
|
```sh
|
|
160
94
|
amont enroll --conventions declared
|
|
161
95
|
```
|
|
162
96
|
|
|
163
|
-
One command per machine: every future `git clone` and `git init` arrives
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
grant safe on a machine that also clones other people's projects, and it
|
|
169
|
-
is the backbone of [rolling amont out to a team](docs/team-rollout.md).
|
|
170
|
-
The manual spelling:
|
|
171
|
-
|
|
172
|
-
```sh
|
|
173
|
-
git config --global init.templateDir ~/.config/git/git-templates/templates
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Git copies that directory into `.git/hooks` on every `init` **and every
|
|
177
|
-
clone**, so from then on every repository you clone runs these hooks without
|
|
178
|
-
being asked again. That is the convenience, and it is worth having.
|
|
179
|
-
|
|
180
|
-
It is also a standing grant, so it is worth stating what you granted. A cloned
|
|
181
|
-
repository can declare its own checks in `amont.conf`, and with this key
|
|
182
|
-
set those are one `amont trust` away from running on your first commit in a
|
|
183
|
-
repository you may have cloned only to read. If you set this, **trust
|
|
184
|
-
deliberately** rather than letting installation be the moment you decided.
|
|
185
|
-
|
|
186
|
-
## One view across every repo
|
|
97
|
+
One command per machine: every future `git clone` and `git init` arrives with
|
|
98
|
+
the hooks. `--conventions declared` keeps the house rules — commit shapes,
|
|
99
|
+
branch names, gates — scoped to repositories that commit an `amont.conf`,
|
|
100
|
+
while the safety net of conflict markers, secrets, oversized files and debug
|
|
101
|
+
leftovers runs everywhere.
|
|
187
102
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
```sh
|
|
196
|
-
amont-fleet install --root ~/Developer # shims into every repo at once
|
|
197
|
-
amont-fleet # report the fleet
|
|
198
|
-
amont-fleet tui # the dashboard above
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
Design record: [the fleet dashboard](docs/fleet-dashboard.md).
|
|
103
|
+
That split is what makes the grant safe on a machine that also clones other
|
|
104
|
+
people's projects. It is still a standing grant, so it is worth stating what
|
|
105
|
+
you granted: a cloned repository's own checks are then one `amont trust` away
|
|
106
|
+
from running on your first commit in a repository you may have cloned only to
|
|
107
|
+
read. **Trust deliberately** rather than letting installation be the moment
|
|
108
|
+
you decided. The full reasoning, and rolling this out to a team:
|
|
109
|
+
[team rollout](docs/team-rollout.md).
|
|
202
110
|
|
|
203
111
|
## Trust: a repository you clone cannot run its own checks
|
|
204
112
|
|
|
205
113
|
`amont.conf` is committed — that is the point, a team shares a check by
|
|
206
|
-
committing
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
So a cloned repository's declared checks are **inert until you say otherwise**:
|
|
114
|
+
committing a line rather than by everybody installing something. So a
|
|
115
|
+
repository you cloned can _declare_ checks, and running them is a decision you
|
|
116
|
+
make, not one `git clone` makes for you.
|
|
211
117
|
|
|
212
118
|
```sh
|
|
213
|
-
amont trust # show what
|
|
214
|
-
amont trust --show # what is trusted
|
|
119
|
+
amont trust # show what it declares, then record it
|
|
120
|
+
amont trust --show # what it declares, and whether it is trusted
|
|
215
121
|
amont trust --revoke
|
|
216
122
|
```
|
|
217
123
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
that the repository's own committed `.gitattributes` asks for, which would let
|
|
223
|
-
a repository choose the transform its own consent is taken through.
|
|
224
|
-
|
|
225
|
-
Full reasoning: [the trust model](docs/trust.md).
|
|
124
|
+
Until then the declarations are **reported, not dropped** — you can see there
|
|
125
|
+
is a decision waiting. Acceptance is recorded against the file's _content_, so
|
|
126
|
+
a `git pull` that adds a command does not inherit the trust you gave the file
|
|
127
|
+
before it. [The trust model](docs/trust.md).
|
|
226
128
|
|
|
227
|
-
##
|
|
129
|
+
## Custom checks, and packs
|
|
228
130
|
|
|
229
|
-
|
|
230
|
-
|
|
131
|
+
A repository declares checks of its own in a committed `amont.conf` — five
|
|
132
|
+
whitespace-separated fields, no shell:
|
|
231
133
|
|
|
232
|
-
```sh
|
|
233
|
-
git config --add hook.skip pre-commit-clippy # that one check
|
|
234
|
-
git config --add hook.skip clippy # that check, on either trigger
|
|
235
|
-
git config --add hook.skip pre-commit # every pre-commit check
|
|
236
134
|
```
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
```sh
|
|
242
|
-
git config amont.severity.clippy warn
|
|
243
|
-
git config amont.severity.pre-commit warn
|
|
135
|
+
# stage name scope severity command
|
|
136
|
+
pre-commit lint-shell *.sh block scripts/lint-shell.sh
|
|
137
|
+
pre-commit rubocop *.rb+.rubocop.yml block rubocop
|
|
138
|
+
pre-push smoke * warn make smoke
|
|
244
139
|
```
|
|
245
140
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
nothing at all, and skipping `lint-js` leaves `lint-json-yaml` alone.
|
|
141
|
+
They run alongside the built-ins, obey the same `hook.skip` and
|
|
142
|
+
`amont.severity` controls, and are inert until trusted.
|
|
249
143
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
144
|
+
The `+` in the scope column splits _what the change touches_ from _what the
|
|
145
|
+
repository carries_: `*.rb+.rubocop.yml` reads "a staged `.rb`, **and** this
|
|
146
|
+
repository has a `.rubocop.yml`". That is what lets a check be safe to hand to
|
|
147
|
+
somebody else.
|
|
253
148
|
|
|
254
|
-
|
|
149
|
+
### Shipping one — packs
|
|
255
150
|
|
|
256
|
-
|
|
257
|
-
|
|
151
|
+
A **pack** is any git repository with an `amont.pack` at its root, written in
|
|
152
|
+
that same syntax. `amont add` vendors its rows into your `amont.conf`:
|
|
258
153
|
|
|
259
154
|
```sh
|
|
260
|
-
amont
|
|
155
|
+
amont add github:fredericrous/amont-pack-java@v1
|
|
261
156
|
```
|
|
262
157
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
them to a teammate.
|
|
158
|
+
What ships is **text, not execution**. The rows land between markers with the
|
|
159
|
+
pack's commit id beside them, the manifest's fingerprint changes, and every
|
|
160
|
+
declared check is inert until you `amont trust` it. Adding a pack is never the
|
|
161
|
+
moment anything becomes runnable.
|
|
268
162
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
The limits measure what you wrote, so a gitmoji never eats your budget, and
|
|
276
|
-
re-running over an amended message changes nothing. Full reference:
|
|
277
|
-
[commit conventions](docs/commit-convention.md#if-the-defaults-do-not-fit).
|
|
163
|
+
Want to write one? [`fredericrous/amont-pack-java`](https://github.com/fredericrous/amont-pack-java)
|
|
164
|
+
is a complete worked example — two rows, one for Maven and one for Gradle, so
|
|
165
|
+
half of it is visibly inert wherever you install it. Its README is the
|
|
166
|
+
long-form authoring guide: gating your rows, what a pack may not carry, and
|
|
167
|
+
how to publish and tag one.
|
|
278
168
|
|
|
279
|
-
|
|
169
|
+
Full reference for both: [custom checks](docs/custom-checks.md).
|
|
280
170
|
|
|
281
|
-
|
|
171
|
+
## Day to day
|
|
282
172
|
|
|
283
|
-
```
|
|
284
|
-
#
|
|
285
|
-
|
|
286
|
-
|
|
173
|
+
```sh
|
|
174
|
+
amont run # would my commit pass? (the staged set)
|
|
175
|
+
amont run --all-files # does my working tree pass? (git ls-files)
|
|
176
|
+
amont check src/main.rs # what is wrong with these FILES — no index, no
|
|
177
|
+
# staging; `file:line: message` an editor can parse
|
|
178
|
+
amont list # what would run here, and why not
|
|
179
|
+
amont restore # bring back unstaged work a killed hook parked
|
|
287
180
|
```
|
|
288
181
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
182
|
+
`amont run --all-files` on a dirty tree reports on content that is not
|
|
183
|
+
committed and may never be — which is what you want when adopting a check into
|
|
184
|
+
an existing repository, where `git add .` is not an acceptable way to measure
|
|
185
|
+
the mess.
|
|
292
186
|
|
|
293
|
-
|
|
187
|
+
Turning one off, or down:
|
|
294
188
|
|
|
295
189
|
```sh
|
|
296
|
-
amont
|
|
297
|
-
|
|
298
|
-
amont run pre-commit-prettier
|
|
299
|
-
amont list # what would run here, and why not
|
|
190
|
+
git config amont.severity.clippy warn # runs, reports, does not block
|
|
191
|
+
git config hook.skip clippy # does not run at all
|
|
300
192
|
```
|
|
301
193
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
not an acceptable way to measure the mess.
|
|
194
|
+
Prefer the downgrade: it keeps the check working and keeps you looking at what
|
|
195
|
+
it finds. [Opting out](docs/opting-out.md) · [configuration](docs/configuration.md)
|
|
196
|
+
· [commit conventions](docs/commit-convention.md).
|
|
306
197
|
|
|
307
|
-
|
|
198
|
+
**What a push actually tests.** By default `pre-push` runs your suite against
|
|
199
|
+
the _working tree_, and says so — fast, and usually what you want, but not what
|
|
200
|
+
you are pushing. `git config amont.testPushedTree true` runs it in a throwaway
|
|
201
|
+
checkout of the commits being pushed instead.
|
|
308
202
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
203
|
+
**For coding agents.** `amont list --json` is the same answer as `amont list`,
|
|
204
|
+
machine-readable: declared and effective severity, whether each check fires
|
|
205
|
+
here and why not, and the command if it is a declared external. `--stage`
|
|
206
|
+
filters to one trigger, `--pushed` scopes to what your next push would carry.
|
|
207
|
+
`amont agents-md` writes the guidance block into `AGENTS.md`.
|
|
208
|
+
[Where the hooks fit in your flow](docs/coding-flow.md).
|
|
312
209
|
|
|
313
|
-
|
|
314
|
-
git config amont.testPushedTree true
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
turns on the accurate answer — the suite runs in a throwaway checkout of the
|
|
318
|
-
commits being pushed, and your tree is not touched. It costs a second checkout
|
|
319
|
-
and a build that cannot reuse your `target/` cache, which is why it is opt-in.
|
|
210
|
+
## One view across every repo
|
|
320
211
|
|
|
321
|
-
|
|
212
|
+
`amont-fleet` — installed separately, on purpose — answers the questions a
|
|
213
|
+
directory full of repositories accumulates: which repos are covered, which
|
|
214
|
+
shims went stale after an upgrade, and which repository is quietly carrying a
|
|
215
|
+
`hook.skip` somebody forgot.
|
|
322
216
|
|
|
323
|
-
|
|
324
|
-
every check's declared and effective severity, whether it fires here and why
|
|
325
|
-
not, and its command if it is a declared external. `--stage` filters to one
|
|
326
|
-
trigger; `--pushed` scopes to what your *next push* would carry (`@{u}..HEAD`)
|
|
327
|
-
rather than the whole tracked tree.
|
|
217
|
+

|
|
328
218
|
|
|
329
219
|
```sh
|
|
330
|
-
amont
|
|
331
|
-
amont
|
|
332
|
-
amont
|
|
220
|
+
amont-fleet install --root ~/Developer # shims into every repo at once
|
|
221
|
+
amont-fleet # report the fleet
|
|
222
|
+
amont-fleet tui # the dashboard above
|
|
223
|
+
amont-fleet fix --root ~/Developer # what drifted (dry run)
|
|
333
224
|
```
|
|
334
225
|
|
|
335
|
-
|
|
336
|
-
span, so the rest of the file stays yours.
|
|
337
|
-
|
|
338
|
-
The block it writes also warns the agent that `git commit` and `git push`
|
|
339
|
-
run their checks first — pre-commit can mean clippy building a workspace,
|
|
340
|
-
pre-push a whole test suite — and an agent whose shell tool defaults to a
|
|
341
|
-
two-minute timeout will kill the command mid-check and read its own
|
|
342
|
-
impatience as a failure. Ten minutes is the safe floor, for both.
|
|
226
|
+
Design record: [the fleet dashboard](docs/fleet-dashboard.md).
|
|
343
227
|
|
|
344
228
|
## Why you can let this near your commits
|
|
345
229
|
|
|
@@ -347,68 +231,61 @@ A prompt theme is cosmetic. This blocks commits and pushes, reads every staged
|
|
|
347
231
|
file, and runs with your credentials while nobody is watching — so the claim it
|
|
348
232
|
has to earn is not "delightful", it is "harmless".
|
|
349
233
|
|
|
350
|
-
- **The commit path links no external crates.** `amont` and
|
|
351
|
-
|
|
352
|
-
that
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
- **
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
- **Over six hundred tests**, run on Linux, macOS and Windows, alongside `cargo fmt
|
|
360
|
-
--check`, `clippy -D warnings`, an MSRV floor of 1.74 compiled for the commit
|
|
361
|
-
path, and `cargo-audit`.
|
|
234
|
+
- **The commit path links no external crates.** `amont` and `amont-runtime`
|
|
235
|
+
are std-only, and `scripts/check-no-deps.sh` fails a build that changes
|
|
236
|
+
that — fails _closed_, so a cargo error or an unreachable registry is a
|
|
237
|
+
failure rather than a reassuring green tick.
|
|
238
|
+
- **No network, ever.** No telemetry, no update checks, no fetches. With the
|
|
239
|
+
commit path std-only there is not even an HTTP client linked to do it with.
|
|
240
|
+
- **Over a thousand tests**, run on Linux, macOS and Windows, alongside
|
|
241
|
+
`cargo fmt --check`, `clippy -D warnings`, an MSRV floor of 1.74 compiled
|
|
242
|
+
for the commit path, and `cargo-audit`.
|
|
362
243
|
- **v1.0.0 followed a full security review**, and each finding landed with a
|
|
363
|
-
committed reproduction
|
|
364
|
-
held-store format that let a repository
|
|
365
|
-
|
|
366
|
-
declarations from; guards that wrote through symlinks onto tracked source; a
|
|
367
|
-
commit subject shaped like a trailer destroying commit trailers;
|
|
368
|
-
`pre-commit-pyright` blocking every commit it ran on.
|
|
244
|
+
committed reproduction — a drive-by RCE via a relative path in the shim, a
|
|
245
|
+
held-store format that let a repository plant a symlink outside the
|
|
246
|
+
worktree, a trust prompt a repository could conceal declarations from.
|
|
369
247
|
- **Your uncommitted work is the thing that must never be lost.** The release
|
|
370
|
-
profile deliberately omits `panic = "abort"` so
|
|
248
|
+
profile deliberately omits `panic = "abort"` so the `Drop` that restores
|
|
371
249
|
unstaged work still runs when a check panics — with a test asserting on the
|
|
372
|
-
manifest, because
|
|
373
|
-
behavioural test could catch the regression.
|
|
250
|
+
manifest, because no behavioural test could catch that regression.
|
|
374
251
|
|
|
375
252
|
Threat model and private reporting: [SECURITY.md](SECURITY.md).
|
|
376
253
|
|
|
377
|
-
## Windows
|
|
378
|
-
|
|
379
|
-
Everything works, and the PowerShell one-liner in [Install](#install) is all
|
|
380
|
-
the setup most machines need. One difference: there is no symlink. To build
|
|
381
|
-
from source instead — Git for Windows ships `bash` and coreutils but not
|
|
382
|
-
`make`:
|
|
383
|
-
|
|
384
|
-
```sh
|
|
385
|
-
cargo build --release
|
|
386
|
-
./target/release/amont install
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
On macOS/Linux `~/.config/git/git-templates` is usually a symlink to the
|
|
390
|
-
checkout, so `init.templateDir` can point at a stable XDG path. Windows does
|
|
391
|
-
not create symlinks without Developer Mode or elevation, so point git straight
|
|
392
|
-
at the checkout instead:
|
|
393
|
-
|
|
394
|
-
```sh
|
|
395
|
-
git config --global init.templateDir 'C:/path/to/amont/templates'
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
Nothing else changes. The shims never need the symlink: they resolve the binary
|
|
399
|
-
at runtime, trying `$GIT_HOOKS_BIN`, the baked path, `~/.local/bin/amont`
|
|
400
|
-
and `~/.local/bin/amont.exe`, then `PATH`.
|
|
401
|
-
|
|
402
254
|
## Requirements
|
|
403
255
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
appears to work and quietly resolves the wrong paths.
|
|
256
|
+
**Git 2.31+** — `git rev-parse --path-format=absolute` landed there, and three
|
|
257
|
+
places depend on it. On an older git those return nothing rather than failing
|
|
258
|
+
loudly, which is the worst shape for a version floor.
|
|
408
259
|
|
|
409
260
|
The hooks are a single binary with no runtime dependencies. Each check brings
|
|
410
261
|
its own tool requirement only where you have opted into that check.
|
|
411
262
|
|
|
263
|
+
Everything works on Windows; the one difference is that there is no symlink,
|
|
264
|
+
so `init.templateDir` points straight at the checkout. [Details](docs/install.md).
|
|
265
|
+
|
|
266
|
+
## The repositories around it
|
|
267
|
+
|
|
268
|
+
Three companions, each its own repository because it runs somewhere amont
|
|
269
|
+
deliberately does not:
|
|
270
|
+
|
|
271
|
+
- [**amont-agent**](https://github.com/fredericrous/amont-agent) — a Claude
|
|
272
|
+
Code `PreToolUse` hook for the mistake no git hook can reach, because it
|
|
273
|
+
lives in the command string itself: `git push … | tail -5` reports tail's
|
|
274
|
+
exit status, so a rejected push reads as success. The guard judges the
|
|
275
|
+
pipeline before it runs. Independent by design — no shared code, and
|
|
276
|
+
neither needs the other; they meet in one optional place, where its
|
|
277
|
+
session notice asks `amont agents-md --check` whether the guidance block
|
|
278
|
+
an agent is about to believe has gone stale.
|
|
279
|
+
- [**attest**](https://github.com/fredericrous/attest) — the CI half of
|
|
280
|
+
`amont.attest`: when every pre-push block gate passed locally, amont
|
|
281
|
+
leaves a **signed** note on the tree it tested, and this single-purpose
|
|
282
|
+
verifier lets CI skip work provably already done. Fail-open by
|
|
283
|
+
construction, and separate precisely so that amont itself never runs in
|
|
284
|
+
CI — [the reasoning](docs/ci.md).
|
|
285
|
+
- [**amont-pack-java**](https://github.com/fredericrous/amont-pack-java) —
|
|
286
|
+
the worked example of [a pack](#shipping-one--packs): how checks amont
|
|
287
|
+
deliberately does not build in get shipped anyway.
|
|
288
|
+
|
|
412
289
|
## Documentation
|
|
413
290
|
|
|
414
291
|
The full documentation is in [`docs/`](docs/), versioned with the code and
|
|
@@ -417,9 +294,10 @@ published as a book:
|
|
|
417
294
|
- [Installing and activating](docs/install.md)
|
|
418
295
|
- [The checks](docs/checks.md) · [Configuration](docs/configuration.md) ·
|
|
419
296
|
[Opting out](docs/opting-out.md)
|
|
420
|
-
- [The trust model](docs/trust.md) · [Custom checks](docs/custom-checks.md)
|
|
297
|
+
- [The trust model](docs/trust.md) · [Custom checks and packs](docs/custom-checks.md)
|
|
421
298
|
- [Where the hooks fit in your flow](docs/coding-flow.md) ·
|
|
422
299
|
[Commit conventions](docs/commit-convention.md) ·
|
|
300
|
+
[CI, and why amont does not run in it](docs/ci.md) ·
|
|
423
301
|
[How it compares](docs/similar-projects.md) ·
|
|
424
302
|
[Ideas, not a roadmap](docs/ideas.md)
|
|
425
303
|
- Decision records for maintainers: [hook architecture](docs/hook-architecture.md),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "amont",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"description": "Opinionated git hooks that judge what you are committing, not what is on disk",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"git",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"node": ">=18"
|
|
33
33
|
},
|
|
34
34
|
"optionalDependencies": {
|
|
35
|
-
"@amont-hooks/darwin-arm64": "1.
|
|
36
|
-
"@amont-hooks/darwin-x64": "1.
|
|
37
|
-
"@amont-hooks/linux-arm64-gnu": "1.
|
|
38
|
-
"@amont-hooks/linux-x64-gnu": "1.
|
|
39
|
-
"@amont-hooks/linux-x64-musl": "1.
|
|
40
|
-
"@amont-hooks/win32-x64": "1.
|
|
35
|
+
"@amont-hooks/darwin-arm64": "1.26.0",
|
|
36
|
+
"@amont-hooks/darwin-x64": "1.26.0",
|
|
37
|
+
"@amont-hooks/linux-arm64-gnu": "1.26.0",
|
|
38
|
+
"@amont-hooks/linux-x64-gnu": "1.26.0",
|
|
39
|
+
"@amont-hooks/linux-x64-musl": "1.26.0",
|
|
40
|
+
"@amont-hooks/win32-x64": "1.26.0"
|
|
41
41
|
}
|
|
42
42
|
}
|