@mu-crew/muzzle 0.1.0 → 0.1.2

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.
@@ -7,6 +7,12 @@
7
7
  // tool_result: read the report, append `muzzle: waited Ws for N slots, ran
8
8
  // Rs` and a `muzzle` custom entry with the same numbers (D26).
9
9
  //
10
+ // One copy per pi process: the pi package and `-e <path>` can both load this
11
+ // file, and two copies would each wrap the call (the CLI also refuses to wrap
12
+ // a command that already runs muzzle, D22). The first copy to load claims
13
+ // GUARD on globalThis; later copies register nothing. The claim is released
14
+ // on session_shutdown, so /reload and session replacement load it again.
15
+ //
10
16
  // Nothing here may block a call: a missing binary or a failing wrap leaves
11
17
  // the call as it is. A throwing tool_call handler blocks the tool in pi, so
12
18
  // every path is caught.
@@ -134,6 +140,9 @@ function wrap(bin: string, command: string, cwd: string, timeout?: number): Prom
134
140
  });
135
141
  }
136
142
 
143
+ /** The process-wide claim; registry-global so separate module copies share it. */
144
+ export const GUARD = Symbol.for("@mu-crew/muzzle/extension");
145
+
137
146
  export interface Deps {
138
147
  findBinary?: () => string | null;
139
148
  tmpRoot?: string;
@@ -142,6 +151,10 @@ export interface Deps {
142
151
  export function createExtension(deps: Deps = {}) {
143
152
  const findBinary = deps.findBinary ?? (() => findMuzzle());
144
153
  return function (pi: ExtensionAPI) {
154
+ const g = globalThis as Record<symbol, unknown>;
155
+ if (g[GUARD] !== undefined) return;
156
+ const claim = {};
157
+ g[GUARD] = claim;
145
158
  let bin: string | null | undefined;
146
159
  let reportDir: string | undefined;
147
160
  const pending = new Map<string, string>();
@@ -167,6 +180,8 @@ export function createExtension(deps: Deps = {}) {
167
180
  if (bin === null) warn(ctx, "muzzle not found: bash calls run unwrapped");
168
181
  }
169
182
  if (bin === null) return;
183
+ // Belt and braces for the guard: our own rewrite is never rewritten.
184
+ if (input.command.startsWith(`${shellQuote(bin)} run `)) return;
170
185
  const timeout = typeof input.timeout === "number" ? input.timeout : undefined;
171
186
  const wrapped = await wrap(bin, input.command, ctx.cwd, timeout);
172
187
  if (wrapWarned) {
@@ -213,6 +228,7 @@ export function createExtension(deps: Deps = {}) {
213
228
  });
214
229
 
215
230
  pi.on("session_shutdown", async () => {
231
+ if (g[GUARD] === claim) delete g[GUARD];
216
232
  if (reportDir) rmSync(reportDir, { recursive: true, force: true });
217
233
  reportDir = undefined;
218
234
  pending.clear();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mu-crew/muzzle",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Per-host admission for heavy commands, with a run log that tunes itself",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -42,8 +42,8 @@
42
42
  }
43
43
  },
44
44
  "optionalDependencies": {
45
- "@mu-crew/muzzle-linux-x64": "0.1.0",
46
- "@mu-crew/muzzle-linux-arm64": "0.1.0",
47
- "@mu-crew/muzzle-darwin-arm64": "0.1.0"
45
+ "@mu-crew/muzzle-linux-x64": "0.1.2",
46
+ "@mu-crew/muzzle-linux-arm64": "0.1.2",
47
+ "@mu-crew/muzzle-darwin-arm64": "0.1.2"
48
48
  }
49
49
  }
@@ -53,8 +53,8 @@ muzzle run --rule gate --run-timeout 900 -- contrib/fast-gate
53
53
  - **`timeout` goes inside `muzzle run`, never outside it.** An outer
54
54
  `timeout` counts the queue wait and kills the gate before it starts. Use
55
55
  `--run-timeout S`, which counts from admission and exits 124.
56
- - In pi, a command that starts with `muzzle ` is left alone by the
57
- extension, so pi's own bash `timeout` still counts the wait. Give a
56
+ - In pi, a command that already runs muzzle (`muzzle run …`, by any
57
+ path) is left alone by the extension, so pi's own bash `timeout` still counts the wait. Give a
58
58
  hand-wrapped call no pi timeout, and put the limit in `--run-timeout`.
59
59
  - muzzle sets `CARGO_BUILD_JOBS`, `RUST_TEST_THREADS`, `MAKEFLAGS` and
60
60
  `MUZZLE_SLOTS` from the claim and overwrites any it inherits. Drop