@groundnuty/macf 0.2.9 → 0.2.10
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/dist/.build-info.json +2 -2
- package/dist/cli/claude-sh.d.ts.map +1 -1
- package/dist/cli/claude-sh.js +105 -3
- package/dist/cli/claude-sh.js.map +1 -1
- package/package.json +2 -2
- package/plugin/rules/coordination.md +11 -1
- package/plugin/rules/mention-routing-hygiene.md +8 -4
- package/scripts/check-mention-routing.sh +93 -6
package/dist/.build-info.json
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/cli/claude-sh.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAG1C;;;;;;;;;;GAUG;AACH,SAAS,gBAAgB,CAAC,GAAoB;IAC5C,QAAQ,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC1B,KAAK,MAAM;YACT,OAAO;gBACL,kCAAkC;gBAClC,8BAA8B,GAAG,CAAC,QAAQ,CAAC,KAAK,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG;aACzE,CAAC;QACJ,KAAK,KAAK;YACR,OAAO;gBACL,iCAAiC;gBACjC,6BAA6B,GAAG,CAAC,QAAQ,CAAC,GAAG,GAAG;aACjD,CAAC;QACJ,KAAK,SAAS;YACZ,OAAO;gBACL,qCAAqC;gBACrC,8BAA8B,GAAG,CAAC,QAAQ,CAAC,IAAI,GAAG;aACnD,CAAC;IACN,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAuB,EACvB,MAAyB,OAAO,CAAC,GAAG;IAEpC,IAAI,GAAG,CAAC,oBAAoB,CAAC,KAAK,GAAG,IAAI,GAAG,CAAC,oBAAoB,CAAC,KAAK,MAAM,EAAE,CAAC;QAC9E,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,oBAAoB,CAAC,IAAI,wBAAwB,CAAC;IAEvE,+DAA+D;IAC/D,kEAAkE;IAClE,6DAA6D;IAC7D,oDAAoD;IACpD,IAAI,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CACb,wDAAwD;YACtD,QAAQ,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI;YACpC,6CAA6C,CAChD,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE;QACF,iFAAiF;QACjF,yEAAyE;QACzE,gFAAgF;QAChF,+EAA+E;QAC/E,mFAAmF;QACnF,uEAAuE;QACvE,wEAAwE;QACxE,qEAAqE;QACrE,wEAAwE;QACxE,yEAAyE;QACzE,sEAAsE;QACtE,yEAAyE;QACzE,kEAAkE;QAClE,2DAA2D;QAC3D,gEAAgE;QAChE,gEAAgE;QAChE,gEAAgE;QAChE,+DAA+D;QAC/D,8DAA8D;QAC9D,uCAAuC;QACvC,8CAA8C;QAC9C,kCAAkC;QAClC,mCAAmC;QACnC,gCAAgC;QAChC,uEAAuE,QAAQ,IAAI;
|
|
1
|
+
{"version":3,"file":"claude-sh.js","sourceRoot":"","sources":["../../src/cli/claude-sh.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.
|
|
3
|
+
"version": "0.2.10",
|
|
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.
|
|
38
|
+
"@groundnuty/macf-core": "0.2.10",
|
|
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>`.**
|
|
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
|
|
@@ -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
|
|
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
|
-
-
|
|
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
|
|
|
@@ -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
|
-
|
|
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
|
-
|
|
141
|
-
|
|
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
|