Commit dd6a5f6
committed
feat(hooks): a hook is a command owned for an interval, and
Adds the background command the feature was asked for — music that plays for
the length of the build and stops when it ends, optionally restarting — by
unifying it with the hooks that already existed rather than bolting a mode
onto them.
## The model
A hook is a command mcpp OWNS FOR AN INTERVAL. The event names the interval.
build_start / build_finished / build_failed opens at the event,
closes when the command exits
during_build opens before the build,
closes after it
The first three are SELF-CLOSING, and "synchronous" stops being a separate
mode: it is what an interval closed by its own command looks like. Everything
that would otherwise be a special case for `during_build` falls out of that one
difference instead of being declared:
* `timeout_seconds` bounds one run, so it does not apply where the build
already bounds it — and is rejected there rather than reinterpreted.
* `loop` restarts a command that ended before its interval did, which a
self-closing interval makes impossible — so it is rejected there too, with
a message naming `during_build`.
* `side_effect` is unchanged. For `during_build`, "failure" means could not
start, or failed to stay up. Being stopped because the interval closed is
not a failure.
`during_build` closes BEFORE the terminal hook, so a "build finished" sound is
not competing with the background music it replaces.
Spelling: every event value is a string or a table (`{ cmd, timeout_seconds }`
or `{ cmd, loop }`) — the string-or-table shape `[dependencies]` and
`[resources].version-info` already use, so no new parsing semantics.
## What it actually cost
The schema was the small half.
1. A PROCESS GROUP. `unix/bounded_process.cppm` killed the direct child, which
is enough for `sh -c "sleep 5"` (the shell execs) and not enough for
`sh -c 'player & wait'` — the shell dies and the player keeps the audio
device. A background player that survives its build, from a process the user
cannot name, is the worst failure this feature can have. POSIX now spawns
with POSIX_SPAWN_SETPGROUP and stops with killpg; Windows already had the
right shape in its job object. The same gap is why `mcpp test --timeout` and
`[build] build_program_timeout` could leave grandchildren behind.
The poller deliberately does NOT reap (waitid WNOWAIT): an unreaped leader
is what keeps the group id from being recycled between the poll and the
kill.
2. A SIGNAL HANDLER. Its own process group is what makes killpg possible AND
what stops the terminal's SIGINT from reaching the child — so Ctrl-C would
have killed mcpp and left the music playing. mcpp had no signal handling at
all; there is now the minimum that is async-signal-safe (a
`volatile sig_atomic_t` group id, killpg, re-raise). Windows gets a console
handler, though its job object already covers process death.
3. A RESTART FLOOR. `loop` on a typo'd command is a fork bomb. 250 ms between
runs, and five consecutive runs that end UNSUCCESSFULLY within a second stop
the loop and report. Both halves matter: an early draft counted short runs
regardless of exit code and killed the build after five restarts of a
perfectly healthy `echo`.
A supervisor thread exists only when `loop = true`.
## Criteria
State, not log lines — "mcpp said it stopped the command" passes whether or not
anything stopped. The e2e asserts the heartbeat file grew and then did not grow
for a further second; that `loop` produces >= 2 runs where its absence produces
exactly 1; that a command which cannot stay up stops and is reported; that
`loop` on `build_start` is refused with a diagnostic naming `during_build`; and
that an interrupted build leaves nothing running. The writer is a GRANDCHILD of
the command mcpp starts, which is the case `kill(pid)` misses and `killpg`
catches. The Ctrl-C case is POSIX-only and prints its skip, because a test that
cannot fail on Windows would read as coverage.
Design: .agents/docs/2026-08-30-project-build-hooks-owned-intervals.mdduring_build
1 parent 9b9f026 commit dd6a5f6
12 files changed
Lines changed: 1409 additions & 87 deletions
File tree
- .agents/docs
- docs
- zh
- modules
- manifest/src
- platform/src
- unix
- windows
- src
- cli
- tests
- e2e
- unit
Lines changed: 193 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2096 | 2096 | | |
2097 | 2097 | | |
2098 | 2098 | | |
2099 | | - | |
2100 | | - | |
| 2099 | + | |
| 2100 | + | |
2101 | 2101 | | |
2102 | 2102 | | |
2103 | 2103 | | |
2104 | 2104 | | |
2105 | 2105 | | |
2106 | 2106 | | |
2107 | 2107 | | |
| 2108 | + | |
| 2109 | + | |
| 2110 | + | |
2108 | 2111 | | |
2109 | 2112 | | |
2110 | 2113 | | |
2111 | 2114 | | |
2112 | 2115 | | |
2113 | 2116 | | |
2114 | | - | |
| 2117 | + | |
2115 | 2118 | | |
2116 | | - | |
2117 | | - | |
2118 | | - | |
2119 | | - | |
| 2119 | + | |
| 2120 | + | |
| 2121 | + | |
| 2122 | + | |
| 2123 | + | |
2120 | 2124 | | |
2121 | 2125 | | |
2122 | 2126 | | |
2123 | | - | |
2124 | | - | |
2125 | | - | |
2126 | | - | |
2127 | | - | |
| 2127 | + | |
| 2128 | + | |
| 2129 | + | |
| 2130 | + | |
| 2131 | + | |
| 2132 | + | |
| 2133 | + | |
| 2134 | + | |
| 2135 | + | |
| 2136 | + | |
| 2137 | + | |
| 2138 | + | |
| 2139 | + | |
| 2140 | + | |
| 2141 | + | |
| 2142 | + | |
| 2143 | + | |
| 2144 | + | |
| 2145 | + | |
| 2146 | + | |
| 2147 | + | |
| 2148 | + | |
| 2149 | + | |
| 2150 | + | |
2128 | 2151 | | |
2129 | 2152 | | |
2130 | 2153 | | |
2131 | 2154 | | |
| 2155 | + | |
2132 | 2156 | | |
2133 | | - | |
2134 | | - | |
| 2157 | + | |
| 2158 | + | |
2135 | 2159 | | |
2136 | 2160 | | |
| 2161 | + | |
| 2162 | + | |
| 2163 | + | |
2137 | 2164 | | |
2138 | 2165 | | |
2139 | 2166 | | |
2140 | 2167 | | |
2141 | 2168 | | |
2142 | 2169 | | |
2143 | 2170 | | |
2144 | | - | |
2145 | | - | |
2146 | | - | |
2147 | | - | |
| 2171 | + | |
| 2172 | + | |
| 2173 | + | |
| 2174 | + | |
| 2175 | + | |
| 2176 | + | |
| 2177 | + | |
| 2178 | + | |
| 2179 | + | |
| 2180 | + | |
| 2181 | + | |
| 2182 | + | |
| 2183 | + | |
| 2184 | + | |
| 2185 | + | |
| 2186 | + | |
| 2187 | + | |
| 2188 | + | |
| 2189 | + | |
| 2190 | + | |
2148 | 2191 | | |
2149 | 2192 | | |
2150 | 2193 | | |
| |||
2162 | 2205 | | |
2163 | 2206 | | |
2164 | 2207 | | |
2165 | | - | |
2166 | | - | |
2167 | | - | |
| 2208 | + | |
| 2209 | + | |
| 2210 | + | |
| 2211 | + | |
2168 | 2212 | | |
2169 | 2213 | | |
2170 | 2214 | | |
| |||
2178 | 2222 | | |
2179 | 2223 | | |
2180 | 2224 | | |
| 2225 | + | |
2181 | 2226 | | |
2182 | 2227 | | |
2183 | 2228 | | |
| |||
2186 | 2231 | | |
2187 | 2232 | | |
2188 | 2233 | | |
| 2234 | + | |
| 2235 | + | |
| 2236 | + | |
| 2237 | + | |
2189 | 2238 | | |
2190 | 2239 | | |
2191 | 2240 | | |
| |||
0 commit comments