@groundnuty/macf 0.2.9 → 0.2.11

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.
@@ -1,4 +1,4 @@
1
1
  {
2
- "commit": "f62d934c26edc72896859557b3109e075f9043c9",
3
- "built_at": "2026-04-30T16:08:13.236Z"
2
+ "commit": "9de68a7ab7403b7d60d9a2c106768edf21365c8f",
3
+ "built_at": "2026-05-01T14:46:30.110Z"
4
4
  }
@@ -1 +1 @@
1
- {"version":3,"file":"claude-sh.d.ts","sourceRoot":"","sources":["../../src/cli/claude-sh.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAiCnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,EAAE,CAkDV;AA4BD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAiGhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM,CAUnF"}
1
+ {"version":3,"file":"claude-sh.d.ts","sourceRoot":"","sources":["../../src/cli/claude-sh.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA8GnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,eAAe,EACvB,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,EAAE,CA+DV;AA4BD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CA+GhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM,CAUnF"}
@@ -41,6 +41,81 @@ function registryEnvLines(cfg) {
41
41
  ];
42
42
  }
43
43
  }
44
+ /**
45
+ * Emit the `macf_settings_get` shell function (macf#313).
46
+ *
47
+ * Reads `.env.<name>` from `<workspace>/.claude/settings.local.json`
48
+ * via `jq`. Returns empty string if the file/key is missing or `jq`
49
+ * isn't installed. Used by the settings-driven identity overrides
50
+ * (see `generateClaudeSh`'s identity block) and the OTel endpoint
51
+ * settings layer.
52
+ *
53
+ * Defined before any caller in the generated script. Idempotent —
54
+ * calling it with no settings.local.json present is safe (just returns
55
+ * empty).
56
+ */
57
+ function settingsGetHelperLines() {
58
+ return [
59
+ '',
60
+ '# Settings-driven identity helper (macf#313). Reads `.env.<NAME>` from',
61
+ '# .claude/settings.local.json via jq; returns empty string if file/key',
62
+ '# missing or jq absent. Used by the identity-override block below + the',
63
+ '# OTel endpoint settings layer to prefer operator-edited settings.local.json',
64
+ '# over baked defaults, without forcing operators to edit this launcher.',
65
+ 'macf_settings_get() {',
66
+ ' local var_name="$1"',
67
+ ' if [ -f "$SCRIPT_DIR/.claude/settings.local.json" ] && command -v jq >/dev/null 2>&1; then',
68
+ ' jq -r ".env.${var_name} // empty" "$SCRIPT_DIR/.claude/settings.local.json" 2>/dev/null',
69
+ ' fi',
70
+ '}',
71
+ ];
72
+ }
73
+ /**
74
+ * Emit the tmux self-wrap block (macf#313).
75
+ *
76
+ * If `$TMUX` is unset (operator launched outside tmux) AND
77
+ * `MACF_NO_TMUX_WRAP` isn't `1`, the script `exec`s itself inside a
78
+ * tmux session named `<MACF_PROJECT>@<MACF_AGENT_NAME>`. Re-attach if
79
+ * the session already exists; otherwise create a new session and exec
80
+ * into it. Eliminates operator-discipline dependency for canonical
81
+ * session naming (coordination.md §Canonical tmux launch pattern).
82
+ *
83
+ * Path-2 promotion of the canonical-session-name rule: pre-#313, the
84
+ * rule existed as text-only doc that operators had to manually wrap
85
+ * `tmux new-session -d -s "<project>@<agent>" "./claude.sh"`. Post-#313,
86
+ * bare `./claude.sh` produces the same canonical session structurally.
87
+ *
88
+ * Order requirement: `MACF_PROJECT` and `MACF_AGENT_NAME` must be
89
+ * exported before this block (so `$SESSION_NAME` resolves correctly).
90
+ * `generateClaudeSh` orders accordingly.
91
+ *
92
+ * Opt-out: `MACF_NO_TMUX_WRAP=1 ./claude.sh` for operator-driven manual
93
+ * launches outside tmux (e.g., debug sessions, single-shot CLI use, CI).
94
+ * Sister convention to `MACF_OTEL_DISABLED=1`, `MACF_SKIP_TOKEN_CHECK=1`.
95
+ */
96
+ function tmuxSelfWrapLines() {
97
+ return [
98
+ '',
99
+ '# Tmux self-wrap (macf#313 Path-2 promotion of coordination.md',
100
+ '# §Canonical tmux launch pattern). If launched outside tmux and the',
101
+ '# operator hasn\'t opted out, re-exec inside a tmux session named',
102
+ '# <MACF_PROJECT>@<MACF_AGENT_NAME>. Attach if the session exists;',
103
+ '# otherwise create a new one. The second invocation (inside tmux)',
104
+ '# has $TMUX set and skips the wrap.',
105
+ '#',
106
+ '# Opt-out: MACF_NO_TMUX_WRAP=1 ./claude.sh',
107
+ '# For operator-driven manual launches outside tmux, debug sessions,',
108
+ '# single-shot CLI use, CI environments.',
109
+ 'if [ -z "${TMUX:-}" ] && [ "${MACF_NO_TMUX_WRAP:-}" != "1" ]; then',
110
+ ' SESSION_NAME="${MACF_PROJECT}@${MACF_AGENT_NAME}"',
111
+ ' if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then',
112
+ ' exec tmux attach -t "$SESSION_NAME"',
113
+ ' else',
114
+ ' exec tmux new-session -s "$SESSION_NAME" -c "$SCRIPT_DIR" "$0" "$@"',
115
+ ' fi',
116
+ 'fi',
117
+ ];
118
+ }
44
119
  /**
45
120
  * Emit the Claude Code native OTEL telemetry env block into the
46
121
  * generated `claude.sh`. Three mandatory gates per Claude Code docs
@@ -126,7 +201,20 @@ export function otelTelemetryLines(config, env = process.env) {
126
201
  'export OTEL_TRACES_EXPORTER=otlp',
127
202
  'export OTEL_METRICS_EXPORTER=otlp',
128
203
  'export OTEL_LOGS_EXPORTER=otlp',
129
- `export OTEL_EXPORTER_OTLP_ENDPOINT="\${OTEL_EXPORTER_OTLP_ENDPOINT:-${endpoint}}"`,
204
+ // 4-layer endpoint resolution chain (macf#313):
205
+ // 1. OTEL_EXPORTER_OTLP_ENDPOINT (runtime env, canonical OTel name) — wins
206
+ // 2. MACF_OTEL_ENDPOINT (runtime env)
207
+ // 3. settings.local.json `.env.MACF_OTEL_ENDPOINT` (operator-edited)
208
+ // 4. Baked default from macf init/update (template-time MACF_OTEL_ENDPOINT)
209
+ // The MACF_OTEL_ENDPOINT runtime+settings layer was added in #313 to
210
+ // close the gap between the existing template-time MACF_OTEL_ENDPOINT
211
+ // (bakes into this script at macf init/update) and the canonical
212
+ // runtime override (OTEL_EXPORTER_OTLP_ENDPOINT). Operators who want
213
+ // per-launch endpoint changes without re-running macf update now have
214
+ // settings.local.json `.env.MACF_OTEL_ENDPOINT` as the ergonomic path.
215
+ `MACF_OTEL_ENDPOINT="\${MACF_OTEL_ENDPOINT:-$(macf_settings_get MACF_OTEL_ENDPOINT)}"`,
216
+ `MACF_OTEL_ENDPOINT="\${MACF_OTEL_ENDPOINT:-${endpoint}}"`,
217
+ 'export OTEL_EXPORTER_OTLP_ENDPOINT="${OTEL_EXPORTER_OTLP_ENDPOINT:-$MACF_OTEL_ENDPOINT}"',
130
218
  'export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf',
131
219
  `export OTEL_SERVICE_NAME="macf-agent-${config.agent_name}"`,
132
220
  `export OTEL_RESOURCE_ATTRIBUTES="gen_ai.agent.name=${config.agent_name},gen_ai.agent.role=${config.agent_role},service.namespace=macf"`,
@@ -179,10 +267,24 @@ export function generateClaudeSh(config) {
179
267
  // cross-repo work — attribution trap fires. See #140 + the
180
268
  // cross-repo cwd trap note in coordination.md Token & Git Hygiene.
181
269
  'export MACF_WORKSPACE_DIR="$SCRIPT_DIR"',
182
- `export MACF_AGENT_NAME="${config.agent_name}"`,
183
270
  `export MACF_PROJECT="${config.project}"`,
184
271
  `export MACF_AGENT_TYPE="${config.agent_type}"`,
185
- `export MACF_AGENT_ROLE="${config.agent_role}"`,
272
+ ...settingsGetHelperLines(),
273
+ '',
274
+ '# Settings-driven identity overrides (macf#313). Three-layer priority:',
275
+ '# 1. Already-set env var (operator: `MACF_AGENT_NAME=foo ./claude.sh`)',
276
+ '# 2. .claude/settings.local.json `env` block (operator: edit JSON;',
277
+ '# no script edit needed; persists across `macf update`)',
278
+ '# 3. Baked default from macf init/update (this template)',
279
+ '# Identity changes become JSON edits rather than script edits.',
280
+ `MACF_AGENT_NAME="\${MACF_AGENT_NAME:-$(macf_settings_get MACF_AGENT_NAME)}"`,
281
+ `MACF_AGENT_NAME="\${MACF_AGENT_NAME:-${config.agent_name}}"`,
282
+ 'export MACF_AGENT_NAME',
283
+ `MACF_AGENT_ROLE="\${MACF_AGENT_ROLE:-$(macf_settings_get MACF_AGENT_ROLE)}"`,
284
+ `MACF_AGENT_ROLE="\${MACF_AGENT_ROLE:-${config.agent_role}}"`,
285
+ 'export MACF_AGENT_ROLE',
286
+ ...tmuxSelfWrapLines(),
287
+ '',
186
288
  `export APP_ID="${config.github_app.app_id}"`,
187
289
  `export INSTALL_ID="${config.github_app.install_id}"`,
188
290
  `export KEY_PATH="${config.github_app.key_path}"`,
@@ -1 +1 @@
1
- {"version":3,"file":"claude-sh.js","sourceRoot":"","sources":["../../src/cli/claude-sh.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude-sh.js","sourceRoot":"","sources":["../../src/cli/claude-sh.ts"],"names":[],"mappings":"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"}
@@ -30,6 +30,20 @@ export declare const MACF_HOOK_COMMAND = "$CLAUDE_PROJECT_DIR/.claude/scripts/ch
30
30
  * `2026-04-27-self-observed-canonical-rule-breach-pattern-analysis.md`).
31
31
  */
32
32
  export declare const MACF_MENTION_HOOK_COMMAND = "$CLAUDE_PROJECT_DIR/.claude/scripts/check-mention-routing.sh";
33
+ /**
34
+ * LGTM-gate hook command (groundnuty/macf#270 — DR-023 UC-2). Blocks
35
+ * `gh pr merge` invocations when the target PR has no non-author
36
+ * APPROVED review on record. Implements `pr-discipline.md` "no LGTM
37
+ * = no merge" structurally (rule codified via macf#262 / PR #263).
38
+ *
39
+ * Per the DR-023 amendment (PR #279), this is a bash command-type
40
+ * hook — NOT `type: "mcp_tool"`. PreToolUse-blocking semantics +
41
+ * mcp_tool's non-blocking-on-disconnect failure mode are structurally
42
+ * incompatible; bash form fires uniformly across substrate (no
43
+ * macf-agent MCP server) AND consumer workspaces. UC-4 (PR #275)
44
+ * demonstrated the bash-form path empirically; UC-2 mirrors it.
45
+ */
46
+ export declare const MACF_LGTM_HOOK_COMMAND = "$CLAUDE_PROJECT_DIR/.claude/scripts/check-lgtm-gate.sh";
33
47
  /**
34
48
  * Permission patterns pre-approving the 4 `macf-agent` plugin skills.
35
49
  * Without these, every first invocation of a skill (e.g. `/macf-status`
@@ -216,15 +230,18 @@ export declare function installPluginSkillPermissions(workspaceDir: string): voi
216
230
  * - `check-gh-token.sh` (groundnuty/macf#140 — attribution-trap defense)
217
231
  * - `check-mention-routing.sh` (groundnuty/macf#244 + #272 — routing
218
232
  * leak detector for raw `@<bot>[bot]` in describing-context)
233
+ * - `check-lgtm-gate.sh` (groundnuty/macf#270 — DR-023 UC-2; blocks
234
+ * `gh pr merge` when no non-author APPROVED review exists)
219
235
  *
220
236
  * Creates the `.claude/` directory and the file if either is missing.
221
237
  * Idempotent: repeated calls don't duplicate entries.
222
238
  *
223
- * Both hooks share `matcher: "Bash"` because Claude Code's matcher field
239
+ * All hooks share `matcher: "Bash"` because Claude Code's matcher field
224
240
  * gates which tool fires the hook; the wrapped-command detection (gh vs
225
- * git-push for token, gh issue/pr comment for routing) happens INSIDE
226
- * each script. Distinct entries per script keep them independently
227
- * upgradeable + diagnosable in `gh issue list` style settings audits.
241
+ * git-push for token, gh issue/pr comment for routing, gh pr merge for
242
+ * LGTM) happens INSIDE each script. Distinct entries per script keep
243
+ * them independently upgradeable + diagnosable in `gh issue list` style
244
+ * settings audits.
228
245
  */
229
246
  export declare function installGhTokenHook(workspaceDir: string): void;
230
247
  //# sourceMappingURL=settings-writer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings-writer.d.ts","sourceRoot":"","sources":["../../src/cli/settings-writer.ts"],"names":[],"mappings":"AAuBA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,0DAA0D,CAAC;AAEzF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,iEAAiE,CAAC;AA6DxG;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAKrD,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAS3E;AAmBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAM3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAM1E;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA+CpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EA0CtD,CAAC;AAWF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA8CzE;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAQlF;AASD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA+BxE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA0C7D"}
1
+ {"version":3,"file":"settings-writer.d.ts","sourceRoot":"","sources":["../../src/cli/settings-writer.ts"],"names":[],"mappings":"AAuBA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,0DAA0D,CAAC;AAEzF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,iEAAiE,CAAC;AAExG;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,2DAA2D,CAAC;AA8D/F;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,EAAE,SAAS,MAAM,EAKrD,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,uBAAuB,kBAAkB,CAAC;AAEvD;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAS3E;AAmBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAM3E;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAM1E;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA+CpE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EA0CtD,CAAC;AAWF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA8CzE;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAQlF;AASD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA+BxE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CA8C7D"}
@@ -52,6 +52,20 @@ export const MACF_HOOK_COMMAND = '$CLAUDE_PROJECT_DIR/.claude/scripts/check-gh-t
52
52
  * `2026-04-27-self-observed-canonical-rule-breach-pattern-analysis.md`).
53
53
  */
54
54
  export const MACF_MENTION_HOOK_COMMAND = '$CLAUDE_PROJECT_DIR/.claude/scripts/check-mention-routing.sh';
55
+ /**
56
+ * LGTM-gate hook command (groundnuty/macf#270 — DR-023 UC-2). Blocks
57
+ * `gh pr merge` invocations when the target PR has no non-author
58
+ * APPROVED review on record. Implements `pr-discipline.md` "no LGTM
59
+ * = no merge" structurally (rule codified via macf#262 / PR #263).
60
+ *
61
+ * Per the DR-023 amendment (PR #279), this is a bash command-type
62
+ * hook — NOT `type: "mcp_tool"`. PreToolUse-blocking semantics +
63
+ * mcp_tool's non-blocking-on-disconnect failure mode are structurally
64
+ * incompatible; bash form fires uniformly across substrate (no
65
+ * macf-agent MCP server) AND consumer workspaces. UC-4 (PR #275)
66
+ * demonstrated the bash-form path empirically; UC-2 mirrors it.
67
+ */
68
+ export const MACF_LGTM_HOOK_COMMAND = '$CLAUDE_PROJECT_DIR/.claude/scripts/check-lgtm-gate.sh';
55
69
  /**
56
70
  * The hook filenames used to identify MACF-managed entries on refresh.
57
71
  * Matched by path-end equality (see isMacfManagedCommand) so operator
@@ -60,6 +74,7 @@ export const MACF_MENTION_HOOK_COMMAND = '$CLAUDE_PROJECT_DIR/.claude/scripts/ch
60
74
  const MACF_HOOK_FILENAMES = [
61
75
  'check-gh-token.sh',
62
76
  'check-mention-routing.sh',
77
+ 'check-lgtm-gate.sh',
63
78
  ];
64
79
  /**
65
80
  * True iff the command string represents one of our managed hooks — i.e.
@@ -493,15 +508,18 @@ export function installPluginSkillPermissions(workspaceDir) {
493
508
  * - `check-gh-token.sh` (groundnuty/macf#140 — attribution-trap defense)
494
509
  * - `check-mention-routing.sh` (groundnuty/macf#244 + #272 — routing
495
510
  * leak detector for raw `@<bot>[bot]` in describing-context)
511
+ * - `check-lgtm-gate.sh` (groundnuty/macf#270 — DR-023 UC-2; blocks
512
+ * `gh pr merge` when no non-author APPROVED review exists)
496
513
  *
497
514
  * Creates the `.claude/` directory and the file if either is missing.
498
515
  * Idempotent: repeated calls don't duplicate entries.
499
516
  *
500
- * Both hooks share `matcher: "Bash"` because Claude Code's matcher field
517
+ * All hooks share `matcher: "Bash"` because Claude Code's matcher field
501
518
  * gates which tool fires the hook; the wrapped-command detection (gh vs
502
- * git-push for token, gh issue/pr comment for routing) happens INSIDE
503
- * each script. Distinct entries per script keep them independently
504
- * upgradeable + diagnosable in `gh issue list` style settings audits.
519
+ * git-push for token, gh issue/pr comment for routing, gh pr merge for
520
+ * LGTM) happens INSIDE each script. Distinct entries per script keep
521
+ * them independently upgradeable + diagnosable in `gh issue list` style
522
+ * settings audits.
505
523
  */
506
524
  export function installGhTokenHook(workspaceDir) {
507
525
  const absDir = resolve(workspaceDir);
@@ -528,6 +546,10 @@ export function installGhTokenHook(workspaceDir) {
528
546
  matcher: 'Bash',
529
547
  hooks: [{ type: 'command', command: MACF_MENTION_HOOK_COMMAND }],
530
548
  },
549
+ {
550
+ matcher: 'Bash',
551
+ hooks: [{ type: 'command', command: MACF_LGTM_HOOK_COMMAND }],
552
+ },
531
553
  ];
532
554
  const updated = {
533
555
  ...settings,
@@ -1 +1 @@
1
- {"version":3,"file":"settings-writer.js","sourceRoot":"","sources":["../../src/cli/settings-writer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings-writer.js","sourceRoot":"","sources":["../../src/cli/settings-writer.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groundnuty/macf",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "Multi-Agent Coordination Framework CLI — coordinate Claude Code agents via GitHub. Installs as `macf` binary; use `macf init` to set up an agent workspace, `macf update` to refresh rules + version pins.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -35,7 +35,7 @@
35
35
  "test:watch": "vitest"
36
36
  },
37
37
  "dependencies": {
38
- "@groundnuty/macf-core": "0.2.9",
38
+ "@groundnuty/macf-core": "0.2.11",
39
39
  "commander": "^14.0.3",
40
40
  "reflect-metadata": "^0.2.2",
41
41
  "zod": "^4.0.0"
@@ -174,8 +174,14 @@ The helper is distributed to every agent workspace by `macf init` and refreshed
174
174
 
175
175
  ### Canonical tmux launch pattern
176
176
 
177
- **One session per agent, named `<project>@<agent>`.** For example:
177
+ **One session per agent, named `<project>@<agent>`.** Post-v0.2.10, `claude.sh` self-wraps in tmux with this naming structurally — bare `./claude.sh` produces the canonical session. Pre-v0.2.10 consumers (and operators wanting manual launch) use the explicit form:
178
178
 
179
+ # Post-v0.2.10 (canonical, structural — recommended for new consumers):
180
+ cd /path/to/academic-resume && ./claude.sh
181
+ # Self-wraps in tmux session "academic-resume@cv-architect" automatically.
182
+ # Re-attaches if the session exists; creates new if not.
183
+
184
+ # Pre-v0.2.10 (manual wrap, still works post-v0.2.10 with MACF_NO_TMUX_WRAP=1):
179
185
  tmux new-session -d -s "academic-resume@cv-architect" \
180
186
  "cd /path/to/academic-resume && ./claude.sh"
181
187
 
@@ -192,6 +198,10 @@ The helper is distributed to every agent workspace by `macf init` and refreshed
192
198
 
193
199
  **Migration** from a single-session multi-window setup: `tmux rename-session -t <old-name> <new-name>` per agent.
194
200
 
201
+ **Path-2 promotion (macf#313, v0.2.10):** the canonical session-naming rule is now structurally enforced by `claude.sh` itself. Consumer workspaces converging on v0.2.10+ via `macf update --plugin` get the self-wrap automatically; substrate launchers (operator-authored, NOT generated by `claude-sh.ts` template) are unaffected. For mixed-version fleets, pre-v0.2.10 consumers continue to need the explicit `tmux new-session` wrap until they update.
202
+
203
+ **Opt-out (post-v0.2.10):** `MACF_NO_TMUX_WRAP=1 ./claude.sh` skips the self-wrap. For operator-driven manual launches outside tmux, debug sessions, single-shot CLI use, CI environments. Sister convention to `MACF_OTEL_DISABLED=1`, `MACF_SKIP_TOKEN_CHECK=1`, `MACF_SKIP_MENTION_CHECK=1`.
204
+
195
205
  ---
196
206
 
197
207
  ## Token & Git Hygiene
@@ -143,6 +143,18 @@ When intentionally bypassing the hook for a knowingly user-attributed op (e.g.,
143
143
 
144
144
  ---
145
145
 
146
+ ## Structural backstop: in-runner token refresh in macf-channel-server (macf#317)
147
+
148
+ The 6 failure modes above all describe **token-acquisition** (the new token coming back wrong); macf#317 surfaced a 7th class — **token-expiry** during long-running sessions. Bot installation tokens have a 1-hour TTL by design; `claude.sh` mints a fresh token at session start and exports `GH_TOKEN`, but **macf-channel-server inherits this fixed token via `process.env` and has no in-runner refresh** absent the macf#317 fix. After 1 hour, every gh-API-using handler (notify_peer's registry lookups, /sign's varsClient calls) 401s. Witnessed 2026-05-01: cv-architect Stop hook 401 at ~67min uptime.
149
+
150
+ The expiry sub-case is **shape-distinct** from modes 1–6: the token is `ghs_*` (right prefix), it was generated correctly, the helper script is installed, the path resolves — it's just stale. Helper-prefix-checking + PreToolUse hooks don't catch it; the structural fix is in-process refresh.
151
+
152
+ **v0.2.11+ defense:** macf-channel-server's `token-refresh.ts` + `refresh-aware-client.ts` modules. The token-refresher caches the current token in-process for ~50 minutes (10-min safety margin under 1hr TTL); on every gh-API call, the refresh-aware client gets a current token (cached or fresh); on 401, the wrapper force-refreshes + retries once. Refresh failures throw with diagnostic — channel-server fails loud rather than silently using a stale token. Implementation cites `silent-fallback-hazards.md Instance 1 (expiry sub-case)` in the diagnostic message so 401s in the field surface the canonical reference.
153
+
154
+ **Operator note:** the structural defense is automatic for consumer-fleet workspaces (npm-installed `@groundnuty/macf-channel-server@0.2.11+`). Substrate workspaces / bash-terminal sessions still need the operator-discipline pattern in `gh-token-refresh.md` ("refresh before every `gh` or `git push`").
155
+
156
+ ---
157
+
146
158
  ## How this relates to other canonical rules
147
159
 
148
160
  - `coordination.md` § "Token & Git Hygiene" documents the canonical helper invocation; this rule provides the failure-mode catalog the helper is designed to defend against.
@@ -110,15 +110,19 @@ The rule is cheap to apply, symmetric across the fleet, and eliminates a class o
110
110
 
111
111
  ## 7. Structural enforcement — `check-mention-routing.sh` PreToolUse hook
112
112
 
113
- Per `groundnuty/macf#244` + `#272` (closed via shared PR), this rule is also enforced by a Claude Code PreToolUse hook on `Bash` tool calls. The hook intercepts `gh issue comment` / `gh pr comment` / `gh issue close --comment` / `gh pr close --comment` invocations, parses the `--body` content, and blocks (`exit 2` with a stderr explanation) when raw `@<bot>[bot]` patterns appear in describing-context positions (mid-line, not backticked, not at line-start).
113
+ Per `groundnuty/macf#244` + `#272`, this rule is enforced by a Claude Code PreToolUse hook on `Bash` tool calls. The hook intercepts `gh issue comment` / `gh pr comment` / `gh issue close --comment` / `gh pr close --comment` invocations, parses the `--body` content, and runs **two checks** that BLOCK (`exit 2` with stderr explanation):
114
+
115
+ - **Check B — must-not-leak (macf#272, shipped PR #275):** raw `@<bot>[bot]` patterns in describing-context positions (mid-line, not backticked, not at line-start) would fire false-positive routing per §5. Applies to all comment-emit subcommands including `gh (issue|pr) close --comment` (leak prevention is independent of recipient semantics).
116
+ - **Check A — must-have-mention (macf#244):** comment bodies with zero routing-active `@<bot>[bot]` mentions silently fail to reach the recipient peer agent per §Communication 2 ("a comment without @mention is invisible to the recipient agent"). Routing-active = NOT wrapped in backticks; both line-start addressing AND mid-line describing-leaks count toward the active total. Applies only to `gh (issue|pr) comment` — close subcommands are bypassed because self-close verification comments are canonically reporter-internal (no recipient).
114
117
 
115
118
  The hook is the same shape as `check-gh-token.sh` (#140 attribution-trap defense) — bash command-type hook distributed via `macf init` / `macf update` / `macf rules refresh` to every workspace's `.claude/scripts/check-mention-routing.sh` with the entry registered in `.claude/settings.json` `hooks.PreToolUse`. Substrate workspaces, tester agents, CV consumers, and future MACF-consumer projects all get the protection uniformly.
116
119
 
117
120
  **Heuristic** (subject to refinement; documented for transparency):
118
121
 
119
- - Already wrapped in backticks (`` `@<bot>[bot]` ``) → allowed (canonical describing form §5)
120
- - At line-start (after optional whitespace, blockquote `>`, or list-item markers `* ` / `- ` / `1. `) → allowed (canonical addressing form §3)
121
- - Otherwise → BLOCK with stderr citing this rule + the offending line + the `MACF_SKIP_MENTION_CHECK=1` operator override
122
+ - Already wrapped in backticks (`` `@<bot>[bot]` ``) → routing-suppressed; allowed (canonical describing form §5); does NOT count toward Check A
123
+ - At line-start (after optional whitespace, blockquote `>`, or list-item markers `* ` / `- ` / `1. `) → routing-active; allowed by Check B (canonical addressing form §3); counts toward Check A
124
+ - Mid-line raw mention routing-active; Check B BLOCK with stderr citing this rule + the offending line + the `MACF_SKIP_MENTION_CHECK=1` operator override
125
+ - Zero routing-active mentions in body (Check A) → BLOCK; only fires when neither line-start addressing nor (any other) routing-active mention is present
122
126
 
123
127
  **Pattern scope (broadened per macf#276):** the hook's `HANDLE_PATTERN` matches ANY `@<handle>[bot]` shape — not just `@macf-*-agent[bot]`. Specifically:
124
128
 
@@ -350,6 +350,38 @@ changed.
350
350
 
351
351
  ---
352
352
 
353
+ ## Structural enforcement — `check-lgtm-gate.sh` PreToolUse hook
354
+
355
+ Per `groundnuty/macf#270` (DR-023 UC-2), the "no LGTM = no merge" rule (codified above in §"How to submit LGTM" + §"When the reviewer is absent or unreachable" + §"Merge-by-implementer") is enforced by a Claude Code PreToolUse hook on `Bash` tool calls. The hook intercepts `gh pr merge` invocations, queries the target PR's review state via `gh pr view --json author,reviews`, and BLOCKs (`exit 2` with stderr explanation) when no APPROVED review from a non-author exists.
356
+
357
+ **Architectural shape (DR-023 amendment 2026-04-27):** this is a bash command-type hook, NOT `type: "mcp_tool"`. PreToolUse-blocking semantics + mcp_tool's non-blocking-on-disconnect failure mode are structurally incompatible — a missing or transiently-disconnected MCP server would silently allow the merge. Bash form fires uniformly across substrate workspaces (where the `macf-agent` MCP server is permanently off per operator directive 2026-04-27) AND consumer workspaces (startup window + transient disconnect periods produce silent-fail paths under mcp_tool). Same reasoning UC-4 (`check-mention-routing.sh`, PR #275) demonstrated empirically.
358
+
359
+ **The hook is the same shape as `check-gh-token.sh` (#140) + `check-mention-routing.sh` (#244 + #272):** a bash script distributed via `macf init` / `macf update` / `macf rules refresh` to every workspace's `.claude/scripts/check-lgtm-gate.sh` with the entry registered in `.claude/settings.json` `hooks.PreToolUse`. Substrate workspaces, tester agents, CV consumers, and future MACF-consumer projects all get the protection uniformly.
360
+
361
+ **Decision rule** (subject to refinement; documented for transparency):
362
+
363
+ - Command does NOT match `gh pr merge` (exact subcommand, wrapper-aware) → allow (other gh subcommands pass through unchanged)
364
+ - Command matches but no PR number can be extracted → allow (defense-in-depth; gh itself surfaces the usage error)
365
+ - Command matches AND `gh pr view --json author,reviews` returns at least one APPROVED review where reviewer login != author login (after normalizing `app/` prefix + `[bot]` suffix) → allow
366
+ - Command matches AND no non-author APPROVED review exists → BLOCK with stderr citing this rule + the missing-LGTM diagnosis + the `MACF_SKIP_LGTM_CHECK=1` operator override
367
+ - Any infrastructure failure (gh missing, network 404/5xx, malformed JSON) → fail-open (allow). Same defense-in-depth posture as `check-gh-token.sh` and `check-mention-routing.sh` — the hook closes residual policy slips, not all merge paths
368
+
369
+ **Wrapper coverage:** the regex matches `gh pr merge` preceded by `sudo`, `env VAR=...`, `watch`, `ionice`, `setsid`, `nice`, `time`, bare-`VAR=...` env-prefix forms, and shell wrappers (`bash -c "gh pr merge ..."`, `sh -c`, `zsh -c`, including flag-prefixed forms like `bash -lc`). Same wrapper allow-list as `check-gh-token.sh` + `check-mention-routing.sh`. Chained-form leadins `;` `|` `&&` covered.
370
+
371
+ **False-positive trade-off:** the hook leans toward false-positive over false-negative on parse-failure paths. PR-number extraction tolerates URL form (`https://github.com/owner/repo/pull/N`), `owner/repo#N` shorthand, and quoted positionals. Bare `gh pr merge` (no positional, gh prompts interactively) passes through unblocked — the operator's discipline catches it because the prompt is visible.
372
+
373
+ **Override (`MACF_SKIP_LGTM_CHECK=1`)** is the escape hatch for legitimate exceptions documented in §"When the reviewer is absent or unreachable":
374
+
375
+ - Reporter-sanctioned self-merge after extended reviewer absence
376
+ - The "PR author offline → reviewer merges with hand-off comment" exception
377
+ - Urgent reverts where waiting for review is itself a hazard
378
+
379
+ Per the `check-gh-token.sh` precedent, structural enforcement plus an escape hatch outperforms behavioral discipline alone.
380
+
381
+ **Empirical motivation:** `groundnuty/macf-testbed#229` Phase C iter 4 sweep (2026-04-26) recorded a self-merge-without-LGTM incident — a tester self-merged when its harness driver (acting as the de-facto reviewer) was killed mid-poll. Codified in §"When the reviewer is absent or unreachable" same day. The hook closes the residual: rule-discipline catches most cases; structural enforcement catches the slips that remain.
382
+
383
+ ---
384
+
353
385
  ## When to modify this rule
354
386
 
355
387
  - **Read:** every session start.
@@ -30,6 +30,12 @@ The trap is that defensive programming targets exit codes, but exit-code success
30
30
  **Recurrence:** 5+ confirmed instances across multiple agents
31
31
  **Canonical defense:** `gh-token-attribution-traps.md` (sister canonical rule) — 6 specific failure modes + result-invariant defenses (`[[ "$GH_TOKEN" == ghs_* ]]` prefix check, `macf-whoami.sh` spot-check, PreToolUse hook intercepts `gh` and `git push` invocations)
32
32
 
33
+ **Sub-case (expiry, macf#317, 2026-05-01):** Bot installation tokens have a **1-hour TTL by design** (GitHub App contract). `claude.sh` mints a fresh token at session start and exports `GH_TOKEN`; the macf-channel-server child process inherits that same env var via standard Node `process.env` pass-through. **Without an in-runner refresh, every gh-API-using handler 401s after ~60 minutes of session uptime.** Detection: 401 (`Bad credentials`) on `listVariables` / `readVariable` / `writeVariable` calls 60+ min after server start. Witnessed 2026-05-01 ~14:30Z on cv-architect's Stop hook at ~67min uptime — the operator-witnessed incident motivating macf#317.
34
+
35
+ This is a distinct sub-case from the missing-helper / mis-pipefail / wrong-prefix attribution-trap modes catalogued in `gh-token-attribution-traps.md`: the agent has the right token *shape* (`ghs_*`) but it's stale. The hazard is structural — session lifetime ≠ token lifetime by design (1hr vs ∞), so any long-running agent eventually hits this.
36
+
37
+ **Defense (macf#317, v0.2.11):** in-process token-refresh helper in macf-channel-server (`src/token-refresh.ts`) caches `{token, mintedAt}`; on every `getRefreshedToken()` call, returns cached if `age < 50min` (10-min safety margin under 1hr TTL), else mints fresh via `macf-gh-token.sh`. The refresh-aware client wrapper (`src/refresh-aware-client.ts`) decorates `GitHubVariablesClient`: every method call gets a refreshed token; on 401, force-refreshes + retries once. Refresh failures throw with diagnostic — never silently fall back to the stale env-var token. Sister-shape: `macf-testbed#135` (sweep-harness in-runner refresh between iterations; closed/deferred for testbed but the channel-server class needed structural defense).
38
+
33
39
  ### Instance 2 — GitHub auto-close negation-blindness
34
40
 
35
41
  **Surface:** PR / issue body markdown parsing
@@ -245,7 +251,7 @@ For coordination-system safety analysis: this is a class of hazards multi-agent
245
251
 
246
252
  | Instance | Surface | Structural defense | Pattern |
247
253
  |---|---|---|---|
248
- | 1 — gh-token attribution traps | `gh` ops + bot tokens | PreToolUse hook + helper-with-fail-loud-prefix-check | Pattern B |
254
+ | 1 — gh-token attribution traps | `gh` ops + bot tokens | PreToolUse hook + helper-with-fail-loud-prefix-check; expiry sub-case (macf#317) adds in-runner token refresh in macf-channel-server (`token-refresh.ts` + `refresh-aware-client.ts`) — caches token ~50min, force-refreshes on 401 | Pattern B (acquisition) + Pattern A (expiry retry) |
249
255
  | 2 — GitHub auto-close negation-blindness | PR/issue body markdown | Pattern B candidate; structural defense via PreToolUse hook on body content per #275 precedent — not yet shipped | Pattern B (latent) |
250
256
  | 3 — Remote Control IPC blocking tmux send-keys | Claude Code TUI input | Two-tier: consumer fleet structurally retired via channel-server primitive (DR-020 mTLS HTTPS POST); substrate fleet permanent operational reality — defense = rule-discipline + Pattern C fragility detector | Pattern C deployable as fragility detector |
251
257
  | 4 — Loki/CH-logs pipeline divergence | OTLP logs routing | manifest warnings + shape-aware diagnostic | Pattern A |
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # check-lgtm-gate.sh — Claude Code PreToolUse hook that blocks
4
+ # `gh pr merge` invocations when no non-author APPROVED review exists
5
+ # on the target PR. Implements `pr-discipline.md` §"How to submit
6
+ # LGTM — formal review, not comment" + §"When the reviewer is absent
7
+ # or unreachable" structurally.
8
+ #
9
+ # Hook contract: JSON on stdin, exit 0 = allow, exit 2 = block (stderr
10
+ # is fed back to Claude as the error). Same shape as #140's
11
+ # check-gh-token.sh + #244/#272's check-mention-routing.sh per
12
+ # groundnuty/macf#270 design alignment.
13
+ #
14
+ # Architectural note (DR-023 amendment 2026-04-27, PR #279): this is a
15
+ # bash command-type hook, NOT `type: "mcp_tool"`. PreToolUse-blocking
16
+ # semantics + mcp_tool's non-blocking-on-disconnect failure mode are
17
+ # structurally incompatible — bash form fires uniformly across substrate
18
+ # (no macf-agent MCP server) AND consumer workspaces (startup window,
19
+ # transient disconnect). Same reasoning UC-4 (PR #275) demonstrated.
20
+ #
21
+ # Override: MACF_SKIP_LGTM_CHECK=1 bypasses (for legitimate operator-
22
+ # allowed exceptions per pr-discipline.md §"When the reviewer is absent
23
+ # or unreachable" — reporter-sanctioned self-merge, urgent revert, etc.).
24
+ #
25
+ # Refs: groundnuty/macf#270 (this hook); pr-discipline.md (canonical
26
+ # rule, distributed via `macf rules refresh`); DR-023 amendment
27
+ # (bash-form decision rule); macf#262 / PR #263 (LGTM rule
28
+ # codification); PR #275 / macf#244+#272 (empirical pattern).
29
+ set -euo pipefail
30
+
31
+ # Cheap exit on operator override — no stdin read, no parsing.
32
+ if [[ "${MACF_SKIP_LGTM_CHECK:-}" == "1" ]]; then
33
+ exit 0
34
+ fi
35
+
36
+ # Read PreToolUse payload. Fall through to allow on parse error — a
37
+ # broken hook must not brick the harness. Same defense-in-depth as
38
+ # check-gh-token.sh.
39
+ INPUT_JSON="$(cat 2>/dev/null || echo "")"
40
+ COMMAND="$(jq -r '.tool_input.command // ""' <<<"$INPUT_JSON" 2>/dev/null || echo "")"
41
+
42
+ if [[ -z "$COMMAND" ]]; then
43
+ # No command extractable — allow (defense-in-depth).
44
+ exit 0
45
+ fi
46
+
47
+ # Wrapper-aware match for `gh pr merge`. Mirrors check-mention-routing.sh's
48
+ # pattern shape — covers sudo, env VAR=, watch, ionice, setsid, nice,
49
+ # time prefix wrappers + chained-form leadins `;` `|` `&`. Subcommand
50
+ # match: `gh pr merge` ONLY (NOT `gh pr view`, `gh pr list`, etc.) —
51
+ # trailing whitespace or end-of-string forces exact-subcommand match.
52
+ GH_MERGE_PATTERN='(^|[[:space:];|&])(sudo[[:space:]]+|env[[:space:]]+([A-Za-z_][A-Za-z_0-9]*=[^[:space:]]*[[:space:]]+)*|watch[[:space:]]+|ionice[[:space:]]+|setsid[[:space:]]+|nice[[:space:]]+|time[[:space:]]+|[A-Za-z_][A-Za-z_0-9]*=[^[:space:]]*[[:space:]]+)*gh[[:space:]]+pr[[:space:]]+merge([[:space:]]|$)'
53
+
54
+ # Shell-wrapper bypass: catches `bash -c "gh pr merge ..."` and variants.
55
+ # Same flag-handling logic as check-gh-token.sh + check-mention-routing.sh.
56
+ SHELL_C_GH_MERGE_PATTERN='(^|[[:space:];|&])(sudo[[:space:]]+|env[[:space:]]+([A-Za-z_][A-Za-z_0-9]*=[^[:space:]]*[[:space:]]+)*|[A-Za-z_][A-Za-z_0-9]*=[^[:space:]]*[[:space:]]+)*(bash|sh|zsh)[[:space:]]+(-[a-zA-Z]+[[:space:]]+)*-[a-zA-Z]*c[[:space:]]+[^[:space:]].*gh[[:space:]]+pr[[:space:]]+merge([[:space:]]|$)'
57
+
58
+ if [[ ! "$COMMAND" =~ $GH_MERGE_PATTERN ]] && [[ ! "$COMMAND" =~ $SHELL_C_GH_MERGE_PATTERN ]]; then
59
+ # Not a `gh pr merge` command — allow.
60
+ exit 0
61
+ fi
62
+
63
+ # Extract PR number from the matched command. The PR number is the
64
+ # first non-flag positional argument after `gh pr merge`. Examples:
65
+ # gh pr merge 123 --squash
66
+ # gh pr merge --squash 123
67
+ # gh pr merge 123 --repo owner/repo --squash --delete-branch
68
+ # bash -c "gh pr merge 123 --squash"
69
+ # We scan the whole command for `gh pr merge` then walk forward to find
70
+ # the first bare integer token (not preceded by `=` so it's not a flag
71
+ # value like `--retries=3`).
72
+ PR_NUMBER=""
73
+ # Strip leading wrappers up to and including `gh pr merge`. Use sed
74
+ # with extended regex to find the gh-pr-merge prefix and remove it.
75
+ TAIL="$(sed -E 's/^.*gh[[:space:]]+pr[[:space:]]+merge[[:space:]]+//' <<<"$COMMAND" 2>/dev/null || echo "")"
76
+ if [[ -z "$TAIL" ]]; then
77
+ # No tail after `gh pr merge` — likely the operator is invoking with
78
+ # no args (interactive prompt). Allow; the command will fail at gh
79
+ # itself with a usage error, not silently merge anything.
80
+ exit 0
81
+ fi
82
+
83
+ # Find the first bare-integer token. Skip flags (`--foo`, `-x`) and
84
+ # their values (handled via `[[ $prev == --* ]]` lookback for non-`=`
85
+ # flag-value form). We only need the FIRST PR number — `gh pr merge`
86
+ # only takes one positional.
87
+ PREV_FLAG=""
88
+ # shellcheck disable=SC2086
89
+ for tok in $TAIL; do
90
+ # Flags introducing a value with a separate-arg form (e.g. `--repo X`)
91
+ # — set PREV_FLAG so the next token is consumed as a value.
92
+ if [[ -n "$PREV_FLAG" ]]; then
93
+ PREV_FLAG=""
94
+ continue
95
+ fi
96
+ # `--flag=value` form — single token, no lookahead needed.
97
+ if [[ "$tok" =~ ^--[a-zA-Z0-9-]+= ]]; then
98
+ continue
99
+ fi
100
+ # `--flag` without `=` — set PREV_FLAG to consume next token as value.
101
+ # Boolean flags (e.g. `--squash`, `--delete-branch`) don't consume a
102
+ # value, but we can't tell from the command alone — heuristic: the
103
+ # first non-flag token AFTER any flags is the PR number, even if we
104
+ # mistakenly skip a boolean's "value." If that "value" is the PR
105
+ # number itself, we miss it; mitigation: gh's canonical positional
106
+ # ordering is `gh pr merge <N> [flags]`, so PR-first is the common
107
+ # form. The few cases that put flags first AND use boolean flags
108
+ # without `=` are rare; fail-open is acceptable per defense-in-depth.
109
+ if [[ "$tok" =~ ^-- ]]; then
110
+ # Known value-taking flags from `gh pr merge --help`:
111
+ # --repo, --body, --body-file, --match-head-commit, --subject,
112
+ # --author-email
113
+ # Boolean flags don't consume a value:
114
+ # --squash, --merge, --rebase, --delete-branch, --auto, --admin,
115
+ # --disable-auto
116
+ case "$tok" in
117
+ --repo|--body|--body-file|--match-head-commit|--subject|--author-email)
118
+ PREV_FLAG="$tok"
119
+ ;;
120
+ *) ;;
121
+ esac
122
+ continue
123
+ fi
124
+ # Short flag — `-X`. Same boolean-vs-value ambiguity. `gh pr merge`
125
+ # short flags from --help: `-s` (squash), `-m` (merge), `-r` (rebase),
126
+ # `-d` (delete-branch), `-R` (repo, value-taking), `-b` (body, value),
127
+ # `-F` (body-file, value), `-t` (subject, value).
128
+ if [[ "$tok" =~ ^-[a-zA-Z]$ ]]; then
129
+ case "$tok" in
130
+ -R|-b|-F|-t)
131
+ PREV_FLAG="$tok"
132
+ ;;
133
+ *) ;;
134
+ esac
135
+ continue
136
+ fi
137
+ # Bare integer — this is our PR number.
138
+ if [[ "$tok" =~ ^[0-9]+$ ]]; then
139
+ PR_NUMBER="$tok"
140
+ break
141
+ fi
142
+ # URL form: `https://github.com/owner/repo/pull/<N>` — gh accepts
143
+ # this as a positional. Extract the trailing integer.
144
+ if [[ "$tok" =~ /pull/([0-9]+) ]]; then
145
+ PR_NUMBER="${BASH_REMATCH[1]}"
146
+ break
147
+ fi
148
+ # `owner/repo#N` shorthand — also accepted by gh.
149
+ if [[ "$tok" =~ \#([0-9]+) ]]; then
150
+ PR_NUMBER="${BASH_REMATCH[1]}"
151
+ break
152
+ fi
153
+ # Quoted forms — strip surrounding quotes before re-checking.
154
+ STRIPPED="${tok#\"}"
155
+ STRIPPED="${STRIPPED%\"}"
156
+ STRIPPED="${STRIPPED#\'}"
157
+ STRIPPED="${STRIPPED%\'}"
158
+ if [[ "$STRIPPED" =~ ^[0-9]+$ ]]; then
159
+ PR_NUMBER="$STRIPPED"
160
+ break
161
+ fi
162
+ done
163
+
164
+ if [[ -z "$PR_NUMBER" ]]; then
165
+ # Couldn't extract a PR number — allow per defense-in-depth.
166
+ # gh itself will fail with a usage error if the command is malformed,
167
+ # OR if it succeeds, the merge happens against the current branch's
168
+ # PR (gh auto-detects) — the LGTM gate is a structural guard, not a
169
+ # 100% catcher. Operator discipline + the canonical rule remain the
170
+ # primary defenses; the hook closes the residual.
171
+ exit 0
172
+ fi
173
+
174
+ # Extract --repo if present so the api call targets the right repo.
175
+ # Without it, `gh api` falls back to the current git remote's repo,
176
+ # which works in most agent-shell flows but breaks for cross-repo merges.
177
+ REPO_FLAG=""
178
+ # Check for `--repo X` (separate-arg form)
179
+ if [[ "$COMMAND" =~ --repo[[:space:]]+([^[:space:]]+) ]]; then
180
+ REPO_FLAG="--repo ${BASH_REMATCH[1]}"
181
+ elif [[ "$COMMAND" =~ --repo=([^[:space:]]+) ]]; then
182
+ REPO_FLAG="--repo ${BASH_REMATCH[1]}"
183
+ elif [[ "$COMMAND" =~ (^|[[:space:]])-R[[:space:]]+([^[:space:]]+) ]]; then
184
+ REPO_FLAG="--repo ${BASH_REMATCH[2]}"
185
+ fi
186
+
187
+ # Query PR author + reviews. Use `gh pr view --json author,reviews`
188
+ # rather than two separate `gh api` calls — single round-trip, gh
189
+ # handles repo detection if --repo was on the original command.
190
+ # Defense-in-depth: any failure (gh missing, network, 404, auth) →
191
+ # fail-open. Same posture as check-gh-token.sh.
192
+ #
193
+ # Strip surrounding quotes from REPO_FLAG's value if quoted.
194
+ PR_JSON=""
195
+ # shellcheck disable=SC2086
196
+ if ! PR_JSON="$(gh pr view "$PR_NUMBER" $REPO_FLAG --json author,reviews 2>/dev/null)"; then
197
+ exit 0
198
+ fi
199
+ if [[ -z "$PR_JSON" ]]; then
200
+ exit 0
201
+ fi
202
+
203
+ # author.login from `gh pr view --json author` returns either the bare
204
+ # login (e.g. "octocat") for users or `app/<name>` for bots (e.g.
205
+ # "app/macf-code-agent"). reviews[].author.login returns the bare
206
+ # login form (e.g. "octocat" or "macf-science-agent" — no `app/`
207
+ # prefix and no `[bot]` suffix). Normalize both to compare reliably:
208
+ # strip `app/` prefix from author and `[bot]` suffix from both sides.
209
+ PR_AUTHOR="$(jq -r '.author.login // ""' <<<"$PR_JSON" 2>/dev/null || echo "")"
210
+ PR_AUTHOR="${PR_AUTHOR#app/}"
211
+ PR_AUTHOR="${PR_AUTHOR%\[bot\]}"
212
+
213
+ if [[ -z "$PR_AUTHOR" ]]; then
214
+ # Couldn't parse author — fail-open.
215
+ exit 0
216
+ fi
217
+
218
+ # Look for at least one APPROVED review where reviewer != author.
219
+ # `gh pr view --json reviews` returns `[{author: {login: "..."}, state: "APPROVED"}, ...]`.
220
+ NON_AUTHOR_APPROVALS="$(
221
+ jq -r --arg author "$PR_AUTHOR" '
222
+ [.reviews[]? |
223
+ select(.state == "APPROVED") |
224
+ (.author.login // "" | sub("^app/"; "") | sub("\\[bot\\]$"; "")) as $reviewer |
225
+ select($reviewer != "" and $reviewer != $author) |
226
+ $reviewer
227
+ ] | length
228
+ ' <<<"$PR_JSON" 2>/dev/null || echo "0"
229
+ )"
230
+
231
+ if [[ -z "$NON_AUTHOR_APPROVALS" ]] || ! [[ "$NON_AUTHOR_APPROVALS" =~ ^[0-9]+$ ]]; then
232
+ # Parse error — fail-open.
233
+ exit 0
234
+ fi
235
+
236
+ if [[ "$NON_AUTHOR_APPROVALS" -ge 1 ]]; then
237
+ # At least one non-author APPROVED review — allow merge.
238
+ exit 0
239
+ fi
240
+
241
+ # No non-author APPROVED review — block.
242
+ cat >&2 <<ERR
243
+ BLOCKED by MACF lgtm-gate hook: PR #${PR_NUMBER} has no non-author APPROVED
244
+ review on record. Per pr-discipline.md "no LGTM = no merge" (canonical rule
245
+ distributed via \`macf rules refresh\`):
246
+
247
+ "Without an explicit LGTM from the reviewer, the implementer does NOT
248
+ merge — even if waiting indefinitely."
249
+
250
+ PR author: ${PR_AUTHOR}
251
+ Non-author APPROVED reviews: 0
252
+
253
+ The LGTM gate is structural — it ensures someone other than the implementer
254
+ has read the diff in context. Self-merge without LGTM bypasses that quality
255
+ gate even if the work is correct.
256
+
257
+ Fix — request a formal review from a peer agent via state-change-firing
258
+ mechanism (NOT a plain comment, per pr-discipline.md §"How to submit LGTM"):
259
+
260
+ gh pr review ${PR_NUMBER} --approve --body "LGTM" # reviewer side
261
+ gh pr review ${PR_NUMBER} --request-changes --body "..." # changes needed
262
+
263
+ Then the reviewer @mentions you on the originating issue with the LGTM
264
+ state-change as the wake signal.
265
+
266
+ Override (ONLY for reporter-sanctioned exceptions per pr-discipline.md
267
+ §"When the reviewer is absent or unreachable"):
268
+ export MACF_SKIP_LGTM_CHECK=1
269
+
270
+ Refs: groundnuty/macf#270 (this hook); pr-discipline.md (canonical rule);
271
+ DR-023 amendment (bash-form decision rule); macf#262 / PR #263 (rule
272
+ codification origin).
273
+ ERR
274
+ exit 2
@@ -57,6 +57,20 @@ if [[ "$COMMAND" =~ gh[[:space:]]+(issue|pr)[[:space:]]+close ]] && [[ ! "$COMMA
57
57
  exit 0
58
58
  fi
59
59
 
60
+ # Track whether this is a `close` subcommand. Check A
61
+ # (must-have-mention; macf#244) does NOT apply to close subcommands —
62
+ # self-close verification comments are canonically no-recipient
63
+ # (reporter-internal verification per coordination.md §Issue Lifecycle 1
64
+ # case 2 self-close pattern: "Verified on main after PR #M merged.
65
+ # Closing as reporter."). The close action itself is the routing-end
66
+ # signal, not a routing-active comment requiring an addressed @mention.
67
+ # Check B (must-not-leak; describing-context) still applies on close
68
+ # subcommands — leak prevention is independent of recipient semantics.
69
+ IS_CLOSE_SUBCOMMAND=false
70
+ if [[ "$COMMAND" =~ gh[[:space:]]+(issue|pr)[[:space:]]+close ]]; then
71
+ IS_CLOSE_SUBCOMMAND=true
72
+ fi
73
+
60
74
  # `--body-file` reads content from a file path; we don't lint file
61
75
  # contents (the file may not exist at hook-fire time, or may be
62
76
  # regenerated). Accept the trade-off and allow. The canonical rule
@@ -105,8 +119,23 @@ fi
105
119
  # benefit (fleet-agnostic protection) is durable.
106
120
  HANDLE_PATTERN='@[a-zA-Z][a-zA-Z0-9_-]*[[]bot[]]'
107
121
 
108
- OFFENDING="$(awk -v pat="$HANDLE_PATTERN" '
122
+ # Single AWK pass produces TWO outputs (line-prefix-discriminated):
123
+ # - `LEAK:<line_no>: <line>` — describing-context leaks (Check B,
124
+ # groundnuty/macf#272). Reported once per offending line.
125
+ # - `ACTIVE_COUNT:<n>` — total routing-active @mentions across the
126
+ # entire body (Check A, groundnuty/macf#244). Routing-active =
127
+ # NOT wrapped in backticks. Both line-start addressing AND mid-line
128
+ # describing-leaks are routing-active; only the backticked form is
129
+ # routing-suppressed. If this count is 0, the comment has no
130
+ # recipient — Check A blocks.
131
+ AWK_OUTPUT="$(awk -v pat="$HANDLE_PATTERN" '
132
+ BEGIN { active_count = 0 }
109
133
  {
134
+ # Track which lines we have already reported a leak for, so a line
135
+ # with multiple offenders surfaces once (existing Check B behavior
136
+ # — preserved verbatim across the Check A extension).
137
+ line_already_reported = 0
138
+
110
139
  # Process every match on this line. After each match, advance the
111
140
  # search-substring past it (RSTART+RLENGTH from the original line $0
112
141
  # tracked via abs_offset).
@@ -120,15 +149,22 @@ OFFENDING="$(awk -v pat="$HANDLE_PATTERN" '
120
149
  char_before = (abs_start - 1 >= 1) ? substr($0, abs_start - 1, 1) : ""
121
150
  char_after = substr($0, abs_end, 1)
122
151
 
123
- # Already-backticked? Allowed describing form (§5).
152
+ # Already-backticked? Allowed describing form (§5). Routing-suppressed
153
+ # — does NOT count toward Check A active-mention total.
124
154
  if (char_before == "`" && char_after == "`") {
125
155
  line = substr(line, RSTART + RLENGTH)
126
156
  abs_offset = abs_start + RLENGTH - 1
127
157
  continue
128
158
  }
129
159
 
160
+ # Routing-active (NOT backticked). Counts toward Check A regardless
161
+ # of position (line-start addressing AND mid-line describing both
162
+ # fire routing — the backtick suppression is the only routing-mute).
163
+ active_count++
164
+
130
165
  # Line-start (after optional whitespace, blockquote, or list-item
131
- # markers)? Allowed addressing form (§3).
166
+ # markers)? Allowed addressing form (§3) — Check B passes; Check A
167
+ # already incremented above.
132
168
  prefix = substr($0, 1, abs_start - 1)
133
169
  if (prefix ~ /^[[:space:]>]*([0-9]+\.[[:space:]]+|[-*][[:space:]]+)?$/) {
134
170
  line = substr(line, RSTART + RLENGTH)
@@ -136,13 +172,27 @@ OFFENDING="$(awk -v pat="$HANDLE_PATTERN" '
136
172
  continue
137
173
  }
138
174
 
139
- # Mid-line raw mention — describing-context leak.
140
- print NR ": " $0
141
- next # skip remaining matches on this line; one report per line
175
+ # Mid-line raw mention — describing-context leak (Check B BLOCK).
176
+ # Report once per line; counter still increments for additional
177
+ # matches on the same line so Check A sees the complete picture.
178
+ if (!line_already_reported) {
179
+ print "LEAK:" NR ": " $0
180
+ line_already_reported = 1
181
+ }
182
+ line = substr(line, RSTART + RLENGTH)
183
+ abs_offset = abs_start + RLENGTH - 1
142
184
  }
143
185
  }
186
+ END { print "ACTIVE_COUNT:" active_count }
144
187
  ' <<<"$COMMAND")"
145
188
 
189
+ # `grep` returns 1 when no matches; under `set -euo pipefail` that
190
+ # propagates as the script's exit code without `|| true`. The Check A
191
+ # happy-path (no leaks) needs OFFENDING to be empty without the hook
192
+ # itself dying — the explicit fall-through is required.
193
+ OFFENDING="$(grep '^LEAK:' <<<"$AWK_OUTPUT" | sed 's/^LEAK://' || true)"
194
+ ACTIVE_COUNT="$(grep '^ACTIVE_COUNT:' <<<"$AWK_OUTPUT" | sed 's/^ACTIVE_COUNT://' || true)"
195
+
146
196
  if [[ -n "$OFFENDING" ]]; then
147
197
  cat >&2 <<ERR
148
198
  BLOCKED by MACF mention-routing-hygiene hook: this comment contains raw
@@ -173,4 +223,41 @@ ERR
173
223
  exit 2
174
224
  fi
175
225
 
226
+ # Check A (groundnuty/macf#244): must-have-mention. Comment-emit commands
227
+ # must contain at least one routing-active @<bot>[bot] mention. Without
228
+ # one, the comment is "invisible" to other agents — coordination.md
229
+ # §Communication 2 names this as the silent-failure mode.
230
+ #
231
+ # Bypassed for `gh (issue|pr) close --comment` — self-close verification
232
+ # comments are canonically no-recipient (reporter-internal). The close
233
+ # action itself signals routing-end; no addressed mention required.
234
+ if [[ "$IS_CLOSE_SUBCOMMAND" == "false" ]] && [[ "$ACTIVE_COUNT" == "0" ]]; then
235
+ cat >&2 <<ERR
236
+ BLOCKED by MACF mention-routing-hygiene hook: this comment has zero
237
+ routing-active @<bot>[bot] mentions. Per coordination.md §Communication 2:
238
+
239
+ "@mention in EVERY comment. Routing depends on it. A comment without
240
+ @mention is invisible to the recipient agent."
241
+
242
+ Without a routing-active mention, the comment is silently invisible to
243
+ peer agents — they have no notification that you posted, even if the
244
+ issue/PR is on their assigned-label queue.
245
+
246
+ Fix: add an addressing mention naming the recipient:
247
+ @<recipient-handle>[bot] <your message>
248
+
249
+ Examples (where <recipient> is the issue reporter, PR reviewer, etc.):
250
+ @macf-science-agent[bot] PR #N ready for review.
251
+ @macf-code-agent[bot] LGTM, you can merge.
252
+
253
+ Override (ONLY for legitimate no-recipient cases — rare; status posts
254
+ on self-filed-self-closed issues, or test-orchestration scratch comments):
255
+ export MACF_SKIP_MENTION_CHECK=1
256
+
257
+ Refs: groundnuty/macf#244 (this check); coordination.md §Communication 2
258
+ (canonical rule, distributed via \`macf rules refresh\`).
259
+ ERR
260
+ exit 2
261
+ fi
262
+
176
263
  exit 0