amont 1.5.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 (3) hide show
  1. package/README.md +440 -0
  2. package/bin/amont.js +82 -0
  3. package/package.json +41 -0
package/README.md ADDED
@@ -0,0 +1,440 @@
1
+ # amont
2
+
3
+ **Catch the bad commit before it exists — and take the whole thing back out in one command.**
4
+
5
+ [![CI](https://github.com/fredericrous/amont/actions/workflows/ci.yaml/badge.svg)](https://github.com/fredericrous/amont/actions/workflows/ci.yaml)
6
+ [![Release](https://img.shields.io/github/v/release/fredericrous/amont?label=release)](https://github.com/fredericrous/amont/releases/latest)
7
+ [![License](https://img.shields.io/github/license/fredericrous/amont)](LICENSE)
8
+
9
+ A single Rust binary that checks `git commit` and `git push` — no YAML to
10
+ write, no runtime to install, nothing to configure before it is useful.
11
+
12
+ - **Useful in the first minute.** Twenty-one built-in checks — commit-message
13
+ conventions, merge-conflict markers, the linters and formatters for the
14
+ languages your repository actually uses, branch rules, your test suite —
15
+ and each one fires only where the repository has opted into its tool.
16
+ - **A cloned repository cannot run code on your machine.** Checks a repository
17
+ declares for itself are inert until you review them and say `amont trust`
18
+ — a gate pre-commit, lefthook and husky do not have.
19
+ - **Nothing on the commit path but `std`.** The hook binary links no external
20
+ crates, and CI fails any build that changes that.
21
+ - **Leaving is one command.** `amont uninstall` removes exactly the four
22
+ shims install wrote; a hook you or another tool put there is named and left
23
+ alone.
24
+
25
+ ![amont catching a commit and letting the fixed one through](docs/assets/amont-demo.gif)
26
+
27
+ How that stacks up against pre-commit, lefthook and husky, feature by feature:
28
+ [the full comparison](docs/similar-projects.md).
29
+
30
+ ## Install
31
+
32
+ **Linux and macOS**
33
+
34
+ ```sh
35
+ curl -fsSL https://raw.githubusercontent.com/fredericrous/amont/main/install/install.sh | sh
36
+ ```
37
+
38
+ **Windows** (PowerShell — the line above is POSIX `sh` and only reaches
39
+ Windows through Git Bash)
40
+
41
+ ```powershell
42
+ irm https://raw.githubusercontent.com/fredericrous/amont/main/install/install.ps1 | iex
43
+ ```
44
+
45
+ Either one downloads a release binary, verifies it against the published
46
+ `SHA256SUMS`, and puts it where the hooks already look — `~/.local/bin`, or
47
+ `%USERPROFILE%\.local\bin`. Both **enable nothing**: hooks are turned on per
48
+ repository, by you, afterwards.
49
+
50
+ ```sh
51
+ cd <your-repo> && amont install # this repository only
52
+ amont list # what would run here, and why not
53
+ ```
54
+
55
+ Prefer not to pipe a script into a shell? Download a binary and its checksum
56
+ from [Releases](https://github.com/fredericrous/amont/releases/latest) —
57
+ prebuilt for Linux (gnu/musl, x86_64 and aarch64), macOS (Intel and Apple
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 four 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
+ four 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).
115
+
116
+ ## What actually runs
117
+
118
+ `amont list` answers that for the repository you are standing in, and it is
119
+ the honest answer rather than the catalogue: most checks are **inert** in most
120
+ repositories, because a repo with no `ruff.toml` never needs ruff.
121
+
122
+ ```
123
+ pre-commit
124
+ ● ban-terms
125
+ ○ cargo-fmt inert here — needs .rs + Cargo.toml
126
+ ● lint-json-yaml
127
+ ● merge-conflict
128
+ ○ prettier inert here — needs .prettierrc | .prettierrc.json | …
129
+ ● usual-name
130
+ pre-push
131
+ ● branch-protect
132
+ ● branch-pattern
133
+ ● pull-rebase
134
+ ○ cargo-test inert here — needs .rs + Cargo.toml
135
+
136
+ ● runs here ○ inert ⊘ skipped via hook.skip ✗ declaration unusable
137
+ ```
138
+
139
+ Twenty-one built-in checks across four git hooks, plus any your repository declares
140
+ itself. The full list, with what each one needs before it fires, is in
141
+ [the checks reference](docs/checks.md).
142
+
143
+ ## Two ways to turn hooks on
144
+
145
+ **Per repository** — the default, and nothing runs anywhere you did not ask:
146
+
147
+ ```sh
148
+ cd <your-repo> && amont install
149
+ amont-fleet install --root ~/Developer # or in bulk, across many repos
150
+ ```
151
+
152
+ `amont install --force` replaces a hook the installer would otherwise
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:
158
+
159
+ ```sh
160
+ git config --global init.templateDir ~/.config/git/git-templates/templates
161
+ ```
162
+
163
+ Git copies that directory into `.git/hooks` on every `init` **and every
164
+ clone**, so from then on every repository you clone runs these hooks without
165
+ being asked again. That is the convenience, and it is worth having.
166
+
167
+ It is also a standing grant, so it is worth stating what you granted. A cloned
168
+ repository can declare its own checks in `amont.conf`, and with this key
169
+ set those are one `amont trust` away from running on your first commit in a
170
+ repository you may have cloned only to read. If you set this, **trust
171
+ deliberately** rather than letting installation be the moment you decided.
172
+
173
+ ## One view across every repo
174
+
175
+ `amont-fleet` — installed separately, on purpose — answers the questions a
176
+ directory full of repositories accumulates: which repos are covered, which
177
+ shims went stale after an upgrade, what every check is doing where, and which
178
+ repository is quietly carrying a `hook.skip` somebody forgot.
179
+
180
+ ![the amont-fleet dashboard scanning a fleet of repositories](docs/assets/fleet-demo.gif)
181
+
182
+ ```sh
183
+ amont-fleet install --root ~/Developer # shims into every repo at once
184
+ amont-fleet # report the fleet
185
+ amont-fleet tui # the dashboard above
186
+ ```
187
+
188
+ Design record: [the fleet dashboard](docs/fleet-dashboard.md).
189
+
190
+ ## Trust: a repository you clone cannot run its own checks
191
+
192
+ `amont.conf` is committed — that is the point, a team shares a check by
193
+ committing it. The consequence is that cloning a repository and committing to
194
+ it would otherwise run commands that repository chose, and neither of those
195
+ acts is one anybody performs *as a decision about trust*.
196
+
197
+ So a cloned repository's declared checks are **inert until you say otherwise**:
198
+
199
+ ```sh
200
+ amont trust # show what this repo declares, and accept it
201
+ amont trust --show # what is trusted here
202
+ amont trust --revoke
203
+ ```
204
+
205
+ The record is keyed on the file's **content**, not its path, so a `git pull`
206
+ that adds a command does not inherit the consent given to the file before it.
207
+ The fingerprint is `git hash-object --no-filters`, and the `--no-filters` is
208
+ not decoration: plain `hash-object` applies the clean filter and eol conversion
209
+ that the repository's own committed `.gitattributes` asks for, which would let
210
+ a repository choose the transform its own consent is taken through.
211
+
212
+ Full reasoning: [the trust model](docs/trust.md).
213
+
214
+ ## Turning a check off, or down
215
+
216
+ Every check has an id, `<trigger>-<name>` — `pre-commit-clippy`. Three things
217
+ name it, and both config surfaces read all three the same way:
218
+
219
+ ```sh
220
+ git config --add hook.skip pre-commit-clippy # that one check
221
+ git config --add hook.skip clippy # that check, on either trigger
222
+ git config --add hook.skip pre-commit # every pre-commit check
223
+ ```
224
+
225
+ `amont.severity.<key>` takes the same three, and keeps the signal — the
226
+ check still runs and still reports, it just stops failing the commit:
227
+
228
+ ```sh
229
+ git config amont.severity.clippy warn
230
+ git config amont.severity.pre-commit warn
231
+ ```
232
+
233
+ Where several keys reach one check the most specific wins: full id, then short
234
+ name, then trigger. Nothing matches by substring — `hook.skip e` reaches
235
+ nothing at all, and skipping `lint-js` leaves `lint-json-yaml` alone.
236
+
237
+ A skipped check is announced on every commit, so a config line nobody remembers
238
+ writing cannot go on silently disabling things. More in
239
+ [opting out](docs/opting-out.md) and [configuration](docs/configuration.md).
240
+
241
+ ## Making the commit convention yours
242
+
243
+ `commit-msg` is the one hook `hook.skip` and `--no-verify` cannot reach, so its
244
+ opinions are adjustable in themselves:
245
+
246
+ ```sh
247
+ amont setup # four questions, current values as the defaults
248
+ ```
249
+
250
+ It asks where the type's gitmoji goes — `none` (the default: your subject,
251
+ untouched), `prefix`, `suffix` or `replace` — and for the subject limit, the
252
+ description budget and the body wrap column. Then it prints the exact
253
+ `git config` lines it wrote, so you can paste them into your dotfiles or hand
254
+ them to a teammate.
255
+
256
+ ```sh
257
+ git config amont.commit.gitmoji suffix # feat: add a cart ✨
258
+ git config amont.commit.descriptionMax 68 # still fits a 72-col subject
259
+ git config amont.commit.bodyWrap 0 # leave my stack traces alone
260
+ ```
261
+
262
+ The limits measure what you wrote, so a gitmoji never eats your budget, and
263
+ re-running over an amended message changes nothing. Full reference:
264
+ [commit conventions](docs/commit-convention.md#if-the-defaults-do-not-fit).
265
+
266
+ ## Custom checks
267
+
268
+ A repository can declare checks of its own in a committed `amont.conf`:
269
+
270
+ ```
271
+ # stage name scope severity command
272
+ pre-commit shellcheck *.sh block scripts/lint-shell.sh
273
+ pre-push smoke * warn make smoke
274
+ ```
275
+
276
+ They run alongside the built-ins, obey the same `hook.skip` and
277
+ `amont.severity` controls, and are inert until trusted. Full reference:
278
+ [custom checks](docs/custom-checks.md).
279
+
280
+ ## Running the checks yourself
281
+
282
+ ```sh
283
+ amont run # would my commit pass? (the staged set)
284
+ amont run --all-files # does my working tree pass? (git ls-files)
285
+ amont run pre-commit-prettier
286
+ amont list # what would run here, and why not
287
+ ```
288
+
289
+ The two questions are different on purpose. `--all-files` on a dirty tree
290
+ reports on content that is not committed and may never be — which is what you
291
+ want when adopting a check into an existing repository, where `git add .` is
292
+ not an acceptable way to measure the mess.
293
+
294
+ ## What a push actually tests
295
+
296
+ By default `pre-push` runs your suite against the **working tree**, and says
297
+ so. That is fast and usually what you want, but it is not what you are pushing:
298
+ an uncommitted fix makes a broken commit look green.
299
+
300
+ ```sh
301
+ git config amont.testPushedTree true
302
+ ```
303
+
304
+ turns on the accurate answer — the suite runs in a throwaway checkout of the
305
+ commits being pushed, and your tree is not touched. It costs a second checkout
306
+ and a build that cannot reuse your `target/` cache, which is why it is opt-in.
307
+
308
+ ## For coding agents
309
+
310
+ `amont list --json` is the same answer as `amont list`, machine-readable:
311
+ every check's declared and effective severity, whether it fires here and why
312
+ not, and its command if it is a declared external. `--stage` filters to one
313
+ trigger; `--pushed` scopes to what your *next push* would carry (`@{u}..HEAD`)
314
+ rather than the whole tracked tree.
315
+
316
+ ```sh
317
+ amont list --json --stage pre-push --pushed
318
+ amont agents-md # write a self-verifying pointer into AGENTS.md
319
+ amont agents-md --check # exit non-zero if it has drifted
320
+ ```
321
+
322
+ `agents-md` only ever touches a `<!-- amont:start -->` / `<!-- amont:end -->`
323
+ span, so the rest of the file stays yours.
324
+
325
+ The block it writes also warns the agent that `git commit` and `git push`
326
+ run their checks first — pre-commit can mean clippy building a workspace,
327
+ pre-push a whole test suite — and an agent whose shell tool defaults to a
328
+ two-minute timeout will kill the command mid-check and read its own
329
+ impatience as a failure. Ten minutes is the safe floor, for both.
330
+
331
+ ## Why you can let this near your commits
332
+
333
+ A prompt theme is cosmetic. This blocks commits and pushes, reads every staged
334
+ file, and runs with your credentials while nobody is watching — so the claim it
335
+ has to earn is not "delightful", it is "harmless".
336
+
337
+ - **The commit path links no external crates.** `amont` and
338
+ `amont-runtime` are std-only, and `scripts/check-no-deps.sh` fails a build
339
+ that changes that — fails *closed*, so a cargo error or an unreachable
340
+ registry is a failure rather than a reassuring green tick. `amont-fleet`
341
+ takes dependencies quite happily; it is installed separately and runs when
342
+ asked.
343
+ - **No network, ever.** The binary phones nothing home — no telemetry, no
344
+ update checks, no fetches. With the commit path std-only, there is not even
345
+ an HTTP client linked to do it with.
346
+ - **Over six hundred tests**, run on Linux, macOS and Windows, alongside `cargo fmt
347
+ --check`, `clippy -D warnings`, an MSRV floor of 1.74 compiled for the commit
348
+ path, and `cargo-audit`.
349
+ - **v1.0.0 followed a full security review**, and each finding landed with a
350
+ committed reproduction: a drive-by RCE via a relative path in the shim; a
351
+ held-store format that let a repository delete a tracked file and plant a
352
+ symlink outside the worktree; a trust prompt a repository could conceal
353
+ declarations from; guards that wrote through symlinks onto tracked source; a
354
+ commit subject shaped like a trailer destroying commit trailers;
355
+ `pre-commit-pyright` blocking every commit it ran on.
356
+ - **Your uncommitted work is the thing that must never be lost.** The release
357
+ profile deliberately omits `panic = "abort"` so that the `Drop` that restores
358
+ unstaged work still runs when a check panics — with a test asserting on the
359
+ manifest, because cargo ignores that setting for test targets and no
360
+ behavioural test could catch the regression.
361
+
362
+ Threat model and private reporting: [SECURITY.md](SECURITY.md).
363
+
364
+ ## Windows
365
+
366
+ Everything works, and the PowerShell one-liner in [Install](#install) is all
367
+ the setup most machines need. One difference: there is no symlink. To build
368
+ from source instead — Git for Windows ships `bash` and coreutils but not
369
+ `make`:
370
+
371
+ ```sh
372
+ cargo build --release
373
+ ./target/release/amont install
374
+ ```
375
+
376
+ On macOS/Linux `~/.config/git/git-templates` is usually a symlink to the
377
+ checkout, so `init.templateDir` can point at a stable XDG path. Windows does
378
+ not create symlinks without Developer Mode or elevation, so point git straight
379
+ at the checkout instead:
380
+
381
+ ```sh
382
+ git config --global init.templateDir 'C:/path/to/amont/templates'
383
+ ```
384
+
385
+ Nothing else changes. The shims never need the symlink: they resolve the binary
386
+ at runtime, trying `$GIT_HOOKS_BIN`, the baked path, `~/.local/bin/amont`
387
+ and `~/.local/bin/amont.exe`, then `PATH`.
388
+
389
+ ## Requirements
390
+
391
+ - **Git 2.31+** — `git rev-parse --path-format=absolute` landed there, and
392
+ three places depend on it. On an older git those return nothing rather than
393
+ failing loudly, which is the worst shape for a version floor: the tool
394
+ appears to work and quietly resolves the wrong paths.
395
+
396
+ The hooks are a single binary with no runtime dependencies. Each check brings
397
+ its own tool requirement only where you have opted into that check.
398
+
399
+ ## Documentation
400
+
401
+ The full documentation is in [`docs/`](docs/), versioned with the code and
402
+ published as a book:
403
+
404
+ - [Installing and activating](docs/install.md)
405
+ - [The checks](docs/checks.md) · [Configuration](docs/configuration.md) ·
406
+ [Opting out](docs/opting-out.md)
407
+ - [The trust model](docs/trust.md) · [Custom checks](docs/custom-checks.md)
408
+ - [Where the hooks fit in your flow](docs/coding-flow.md) ·
409
+ [Commit conventions](docs/commit-convention.md) ·
410
+ [How it compares](docs/similar-projects.md) ·
411
+ [Ideas, not a roadmap](docs/ideas.md)
412
+ - Decision records for maintainers: [hook architecture](docs/hook-architecture.md),
413
+ [index fidelity and run modes](docs/index-fidelity-and-run-modes.md),
414
+ [skip management](docs/hook-skip-management.md),
415
+ [the fleet dashboard](docs/fleet-dashboard.md),
416
+ [the Rust migration](docs/rust-migration.md)
417
+
418
+ ## Contributing
419
+
420
+ Everything is Rust, in `crates/`:
421
+
422
+ ```
423
+ crates/amont-runtime/ the checks, registry and dispatchers. std only.
424
+ crates/amont/ the hook binary. Runs on every commit. std only.
425
+ crates/amont-fleet/ the dashboard and the fleet fixer. Opt-in.
426
+ ```
427
+
428
+ `make check` is the CI-parity target — run it before you push. Setup, the
429
+ zero-dependency rule and when reopening it is legitimate, the house test style
430
+ and the commit convention are all in [CONTRIBUTING.md](CONTRIBUTING.md).
431
+
432
+ Questions, "does this work with X", ideas for checks:
433
+ [Discussions](https://github.com/fredericrous/amont/discussions). Bugs:
434
+ [issues](https://github.com/fredericrous/amont/issues).
435
+
436
+ By participating you agree to the [Code of Conduct](CODE_OF_CONDUCT.md).
437
+
438
+ ## License
439
+
440
+ [MIT](LICENSE).
package/bin/amont.js ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ // Find the native binary npm installed for this platform, and become it.
3
+ //
4
+ // This wrapper exists only because a package manager can link a `bin` that
5
+ // lives inside the package, and the native executable lives in a DIFFERENT
6
+ // package — one of six, selected by npm from `os`/`cpu`/`libc`.
7
+ //
8
+ // It is not on the hook path. `amont init` bakes `current_exe()` — the native
9
+ // binary this spawns, not this file — into `.git/hooks`, so the ~30ms of node
10
+ // start-up below is paid once during `prepare` and never again on a commit.
11
+ // See npm/README.md.
12
+
13
+ const { spawnSync } = require("node:child_process");
14
+ const { existsSync } = require("node:fs");
15
+
16
+ // The same six targets `release.yaml` builds, spelled the way npm spells them.
17
+ // `libc` is why linux-x64 appears twice: a musl host cannot run the glibc build,
18
+ // and npm will install only the package whose `libc` matches.
19
+ const PACKAGES = {
20
+ "darwin arm64": "amont-darwin-arm64",
21
+ "darwin x64": "amont-darwin-x64",
22
+ "linux arm64": "amont-linux-arm64-gnu",
23
+ "linux x64": ["amont-linux-x64-gnu", "amont-linux-x64-musl"],
24
+ "win32 x64": "amont-win32-x64",
25
+ };
26
+
27
+ function candidates() {
28
+ const found = PACKAGES[`${process.platform} ${process.arch}`];
29
+ if (!found) return [];
30
+ return Array.isArray(found) ? found : [found];
31
+ }
32
+
33
+ // `require.resolve` rather than a hand-built `../amont-<target>/bin/…` path.
34
+ // pnpm does not hoist — the real package sits under `node_modules/.pnpm/` — so a
35
+ // path assembled from `__dirname` is correct under npm and wrong under pnpm and
36
+ // yarn. Node's own resolver knows where the dependency actually is.
37
+ function resolveBinary() {
38
+ const exe = process.platform === "win32" ? "amont.exe" : "amont";
39
+ for (const pkg of candidates()) {
40
+ try {
41
+ const p = require.resolve(`${pkg}/bin/${exe}`);
42
+ if (existsSync(p)) return p;
43
+ } catch {
44
+ // Not installed: either the wrong libc for this host, or an
45
+ // `--ignore-scripts`-style install that skipped optional deps. Try the
46
+ // next candidate before giving up.
47
+ }
48
+ }
49
+ return null;
50
+ }
51
+
52
+ const binary = resolveBinary();
53
+ if (!binary) {
54
+ // Name the platform. "amont binary not found" sends people to reinstall;
55
+ // "no build for linux/ppc64" tells them the actual answer, which is that they
56
+ // want `cargo install amont` or the shell installer.
57
+ const target = `${process.platform}/${process.arch}`;
58
+ process.stderr.write(
59
+ `amont: no native binary for ${target}.\n` +
60
+ ` npm installs one of: ${Object.values(PACKAGES).flat().join(", ")}\n` +
61
+ ` If your platform is not among them, build from source:\n` +
62
+ ` cargo install amont\n` +
63
+ ` If it is, the optional dependency did not install — try:\n` +
64
+ ` npm install --force amont\n`,
65
+ );
66
+ process.exit(1);
67
+ }
68
+
69
+ // `spawnSync` with inherited stdio rather than `execFileSync`: this forwards the
70
+ // child's exit CODE, and a hook runner's exit code is the whole product. It also
71
+ // keeps the child's stdin, which `amont run` reads.
72
+ const result = spawnSync(binary, process.argv.slice(2), { stdio: "inherit" });
73
+ if (result.error) {
74
+ process.stderr.write(`amont: could not run ${binary}: ${result.error.message}\n`);
75
+ process.exit(1);
76
+ }
77
+ // A signalled child has a null status. Report it the way a shell does, so
78
+ // "killed by SIGINT" does not read as a clean exit 0.
79
+ if (result.status === null && result.signal) {
80
+ process.exit(128 + (require("node:os").constants.signals[result.signal] ?? 0));
81
+ }
82
+ process.exit(result.status ?? 1);
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "amont",
3
+ "version": "1.5.0",
4
+ "description": "Opinionated git hooks that judge what you are committing, not what is on disk",
5
+ "keywords": [
6
+ "git",
7
+ "git-hooks",
8
+ "pre-commit",
9
+ "pre-push",
10
+ "hooks",
11
+ "lint",
12
+ "husky"
13
+ ],
14
+ "homepage": "https://github.com/fredericrous/amont#readme",
15
+ "bugs": "https://github.com/fredericrous/amont/issues",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/fredericrous/amont.git"
19
+ },
20
+ "license": "MIT",
21
+ "author": "Frederic Rousseau",
22
+ "type": "commonjs",
23
+ "bin": {
24
+ "amont": "bin/amont.js"
25
+ },
26
+ "files": [
27
+ "bin/amont.js",
28
+ "README.md"
29
+ ],
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "optionalDependencies": {
34
+ "amont-darwin-arm64": "1.5.0",
35
+ "amont-darwin-x64": "1.5.0",
36
+ "amont-linux-arm64-gnu": "1.5.0",
37
+ "amont-linux-x64-gnu": "1.5.0",
38
+ "amont-linux-x64-musl": "1.5.0",
39
+ "amont-win32-x64": "1.5.0"
40
+ }
41
+ }