simt-dev 0.1.0 → 0.1.1
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/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,32 @@ All notable changes to this package are recorded here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project follows
|
|
5
5
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.1.1] — 2026-10-11
|
|
8
|
+
|
|
9
|
+
### A foreign hook on an event this repo does not gate is chained
|
|
10
|
+
|
|
11
|
+
`0.1.0` chained the wrong set of hooks and is worth replacing rather than
|
|
12
|
+
recommending. It chained on the event *vocabulary* — anything that was not
|
|
13
|
+
`pre-commit` or `pre-push` — when the question worth asking is whether **this
|
|
14
|
+
repository** declares a gate for that event.
|
|
15
|
+
|
|
16
|
+
The difference is `simt-app`, whose `pre-push` is `git-lfs`. `pre-push` is an
|
|
17
|
+
event this tool gates in general, so `0.1.0` displaced that hook; and because
|
|
18
|
+
`simt-app` declares no `pre-push` gate there was no shim for the event either, so
|
|
19
|
+
git would have found no `pre-push` hook at all. LFS objects would have stopped
|
|
20
|
+
being uploaded, with nothing to notice it — the exact silent failure chaining
|
|
21
|
+
exists to prevent, reached by fixing the wrong half of it.
|
|
22
|
+
|
|
23
|
+
`0.1.1` asks the manifest. An event the repo declares a gate for is left to
|
|
24
|
+
`gates.commands`, where the hook runs as a gate and its verdict appears in the
|
|
25
|
+
report; every other foreign hook is chained. That also picks up
|
|
26
|
+
`simt-landing`'s Lighthouse pre-push, which declares no gates at all.
|
|
27
|
+
*(ADR-018, as amended)*
|
|
28
|
+
|
|
29
|
+
Upgrade with `npm i -D simt-dev@0.1.1`, then `simt hooks install --yes`. Any
|
|
30
|
+
repository already routed with `0.1.0` should re-run it: the shims it writes
|
|
31
|
+
will differ where a gated event was previously displaced.
|
|
32
|
+
|
|
7
33
|
## [0.1.0] — 2026-10-11
|
|
8
34
|
|
|
9
35
|
The first release with real contents in it. `1.0.0` was an empty reservation of the name
|
|
@@ -100,4 +126,5 @@ never ran `simt hooks install` again will find nothing until the dependency is r
|
|
|
100
126
|
and `simt hooks install --yes` is re-run. That is a real upgrade step and it is called out
|
|
101
127
|
here rather than discovered.
|
|
102
128
|
|
|
129
|
+
[0.1.1]: https://github.com/QuazarMedia/simt-dev/releases/tag/v0.1.1
|
|
103
130
|
[0.1.0]: https://github.com/QuazarMedia/simt-dev/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -23,13 +23,13 @@ Requires **Node >= 22.20.0**.
|
|
|
23
23
|
|
|
24
24
|
```sh
|
|
25
25
|
# pinned, per repository - what CI and a teammate both get
|
|
26
|
-
npm i -D simt-dev@0.1.
|
|
26
|
+
npm i -D simt-dev@0.1.1
|
|
27
27
|
|
|
28
28
|
# or globally, if you would rather not add a dependency
|
|
29
|
-
npm i -g simt-dev@0.1.
|
|
29
|
+
npm i -g simt-dev@0.1.1
|
|
30
30
|
|
|
31
31
|
# or with no install at all, for a one-off
|
|
32
|
-
npx -y simt-dev@0.1.
|
|
32
|
+
npx -y simt-dev@0.1.1 check
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
Pin the version. The tool writes a content digest into the files it generates, and an
|
|
@@ -121,13 +121,23 @@ question, which is why fixing the shared one changed nothing visible.
|
|
|
121
121
|
hook is not there at all, the shim refuses and names the path — a hook that
|
|
122
122
|
silently stops running is the exact outcome this ruling exists to prevent.
|
|
123
123
|
|
|
124
|
-
A gate-type foreign hook is deliberately **not** chained
|
|
125
|
-
|
|
126
|
-
`gates.commands
|
|
127
|
-
run it *after* the gates passed, outside
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
a
|
|
124
|
+
A gate-type foreign hook is deliberately **not** chained — *when this repository
|
|
125
|
+
declares a gate for that event*. The dispatcher replaces the hook there by design, the
|
|
126
|
+
hook's real place is `gates.commands`, and its verdict belongs in the gate report next
|
|
127
|
+
to the others. Chaining it would run it *after* the gates had already passed, outside
|
|
128
|
+
anything the author sees.
|
|
129
|
+
|
|
130
|
+
"Does this tool gate it" is a fact about the manifest, not about the event vocabulary,
|
|
131
|
+
and reading it the second way cost `simt-app` its `pre-push`. That hook is git-lfs.
|
|
132
|
+
`pre-push` is an event this tool gates *in general*, so a vocabulary check displaced it
|
|
133
|
+
— and because `simt-app` declares no `pre-push` gate there is no shim for that event
|
|
134
|
+
either, so git would have found no `pre-push` hook at all. LFS objects would have
|
|
135
|
+
stopped being uploaded, with nothing to notice it: the same silent failure this ruling
|
|
136
|
+
exists to prevent, reached by fixing the wrong half of it. The test asks the manifest.
|
|
137
|
+
|
|
138
|
+
The install note says which of the two happened, because "stopped running" was wrong
|
|
139
|
+
about a carried hook and would have pushed an operator to restore a hook that was
|
|
140
|
+
already running for them.
|
|
131
141
|
|
|
132
142
|
## Consequences
|
|
133
143
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "simt-dev",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Shared agent rules, skills and git hooks for a repository: one command adopts a repo, and every gate it declares is probed before it is written.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Said Elimam",
|
|
@@ -39,7 +39,5 @@
|
|
|
39
39
|
"scripts": {
|
|
40
40
|
"test": "node --test test/*.test.mjs",
|
|
41
41
|
"lint": "node bin/simt-dev.mjs doctor"
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
"devDependencies": {}
|
|
45
|
-
}
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/commands/hooks.mjs
CHANGED
|
@@ -169,19 +169,33 @@ async function installHooks(root, flags) {
|
|
|
169
169
|
// stop running - and they stop running silently, which is why they are planned here
|
|
170
170
|
// rather than left to the operator to notice (ADR-018, as amended).
|
|
171
171
|
//
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
172
|
+
// "Does not gate" is a fact about THIS repository: `gateCount` asks what its manifest
|
|
173
|
+
// declares for that event, so an event outside the known vocabulary (post-commit) and
|
|
174
|
+
// an event the repo simply leaves empty (a pre-push with no gates) are both chained,
|
|
175
|
+
// while an event the repo does gate is left to the manifest's gates.commands - there
|
|
176
|
+
// the hook runs as a gate and its verdict appears in the report beside the others,
|
|
177
|
+
// rather than after the gates passed where an author cannot see it.
|
|
178
|
+
//
|
|
179
|
+
// Keying this on the event vocabulary instead of on the manifest cost simt-app its
|
|
180
|
+
// git-lfs hook: pre-push is a gated event in general, but this repo declares no
|
|
181
|
+
// pre-push gate, so nothing replaces its hook and routing would have dropped it.
|
|
175
182
|
const chained = [
|
|
176
183
|
// Already chained by an earlier install, read back off disk: re-rendered from the
|
|
177
184
|
// file's own contents so the bytes cannot drift on a second run.
|
|
178
185
|
...(await Promise.all(
|
|
179
186
|
state.chained.map(async (c) => ({ event: c.event, target: await relativeTarget(root, c.target) })),
|
|
180
187
|
)),
|
|
181
|
-
//
|
|
188
|
+
// Foreign hooks on events THIS repo has no gate for.
|
|
189
|
+
//
|
|
190
|
+
// Per repository, not per event vocabulary - and the difference is not academic.
|
|
191
|
+
// simt-app declares no pre-push gate, and its pre-push is git-lfs: routing without a
|
|
192
|
+
// shim for that event means git finds no pre-push hook at all and LFS objects stop
|
|
193
|
+
// being uploaded, silently, with nothing to notice it. An event this repo gates is
|
|
194
|
+
// different: the dispatcher replaces the hook there by design, and the hook's real
|
|
195
|
+
// place is gates.commands.
|
|
182
196
|
...(await Promise.all(
|
|
183
197
|
state.foreign
|
|
184
|
-
.filter((f) =>
|
|
198
|
+
.filter((f) => gateCount(manifest, f.event) === 0)
|
|
185
199
|
.map(async (f) => ({ event: f.event, target: await relativeTarget(root, f.path) })),
|
|
186
200
|
)),
|
|
187
201
|
].reduce((all, c) => (all.some((x) => x.event === c.event) ? all : [...all, c]), []);
|