Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ Run `python3 <skill>/scripts/<name>` (`bash` for `.sh`). `name: purpose — argu
- vacuous_test_gate.py: a changed test file must really run and assert. — [REPORT] (--changed PATH... | --base…
- vendor_drift.py: list vendored skill files in TARGET that differ from the… — TARGET [--src DIR]
- wired_check.py: warn when a NEW script has no caller. — BASE HEAD [--root DIR]
- No documented CLI: _clean_union.sh, _dirty_guard.sh, _lock.sh, admission_check.py, board_common.py, bypass_guard.py, ceo_altitude_guard.py, comms_guard.py, context_nudge.py, cost_statusline.py, decision_gate.py, destructive_guard.py, destructive_guard_core.py, finding_guard.py, flake_ledger.py, freeze_hook.py, gh_rest.py, handback_cap.py, handoff_inject.py, heavy_gate.py, host_accept.py, host_installer.py, host_safety.py, landing_watchdog.py, lane_cap.py, lane_resume_nudge.py, lkg.py, outcome_claim_guard.py, peer_ack.py, perun_auto_update.py, pipe_mask_guard.py, pipeline_profile.py, plan_gate.py, pregate_parity.py, red_main.py, repeat_poll_guard.py, reply_cap.py, restore_ledger.py, scope_creep_check.py, session_brief.py, stall_guard.py, subagent_brief_lint.py, surface_check.py, terse_reply_check.py
- No documented CLI: _clean_union.sh, _dirty_guard.sh, _lock.sh, admission_check.py, board_common.py, bypass_guard.py, ceo_altitude_guard.py, comms_guard.py, context_nudge.py, cost_statusline.py, decision_gate.py, destructive_guard.py, destructive_guard_core.py, finding_guard.py, flake_ledger.py, freeze_hook.py, gh_rest.py, handback_cap.py, handoff_inject.py, heavy_gate.py, host_accept.py, host_installer.py, host_safety.py, landing_watchdog.py, lane_cap.py, lane_resume_nudge.py, lkg.py, outcome_claim_guard.py, peer_ack.py, perun_auto_update.py, pipe_mask_guard.py, pipeline_profile.py, plan_gate.py, pregate_parity.py, privacy_guard.py, red_main.py, repeat_poll_guard.py, reply_cap.py, restore_ledger.py, scope_creep_check.py, session_brief.py, stall_guard.py, subagent_brief_lint.py, surface_check.py, terse_reply_check.py

### business-ops
- bizops_check.py: Deterministic arithmetic checks business-ops already states… — [input.json] (stdin when no path)
Expand Down
1 change: 1 addition & 0 deletions .claude/skills/agentic-delivery/INDEX-scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Generated by `scripts/skill_index.py` (do not hand-edit). The script half of `IN
| `scripts/premise_check.py` | before handing PRs or issues to a lane or peer, say which are already done or stale. | premise_check.py N [N ...] [--repo OWNER/NAME] [--timeout S] |
| `scripts/prevention_lint.py` | every prevention/action item needs an owner, a tracking id and a verifiable end state. | prevention_lint.py FILE.md |
| `scripts/priority_gate.py` | no presentation-only PR while an aged P0/mechanism issue has no PR citing it. | priority_gate.py --labels-json FILE [options] priority_gate.py --repo OWNER/REPO --pr N [options] priority_gate.py --se… |
| `scripts/privacy_guard.py` | PreToolUse(Bash) hook: DENY a GitHub write whose title or body matches the repo's banlist (a write… | — |
| `scripts/queue_guard.py` | single priority queue: print the next issue to pull, flag P0 inflation. | queue_guard.py --issues issues.json --priorities PRIORITIES.md [--max-unranked N] issues.json gh issue list --json numb… |
| `scripts/reap_own.sh` | kill your own dev servers older than MAX_AGE_S whose cwd is under ROOT (your own lane or session tr… | reap_own.sh |
| `scripts/red_main.py` | green-main alarm: every red test on the default branch needs a fix or an owner within 1h. | — |
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/agentic-delivery/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ Generated by `scripts/skill_index.py` (do not hand-edit; rerun it after changing

## Scripts

109 scripts. Read `INDEX-scripts.md` when you need a script (a trigger and CLI per script). `../INDEX.md`, `### agentic-delivery`, has only each one-line purpose and arguments.
110 scripts. Read `INDEX-scripts.md` when you need a script (a trigger and CLI per script). `../INDEX.md`, `### agentic-delivery`, has only each one-line purpose and arguments.
44 changes: 32 additions & 12 deletions .claude/skills/agentic-delivery/scripts/comms_guard.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,22 @@
REST = re.compile(r"(?:\bcurl\b|\bgh\s+api\b)[\s\S]{0,600}?\brepos/[^/\s'\"]+/[^/\s'\"]+/(pulls|issues)((?:/\d+)?(?:/(?:comments|reviews))?)(?=[\s'\"?]|$)")
HEREDOC = re.compile(r"<<-?[ \t]*(['\"]?)(\w+)\1[ \t]*\n(.*?)\n[ \t]*\2[ \t]*(?=\n|\)|\"|'|$)", re.S)
VALUE = re.compile(r"\"((?:[^\"\\]|\\.)*)\"|'([^']*)'|(\S+)", re.S)
QUOTED = re.compile(r"\\.|'[^']*'|\"(?:[^\"\\]|\\.)*\"", re.S) # an escape, or a complete quoted string


def _plain(tail, keep=None):
"""`tail` with each heredoc body and each quoted string blanked to NULs, the same length so offsets line up; `keep(string)` true
spares a quoted string. Stray quotes in a heredoc body pair with nothing, and an unclosed quote hides nothing."""
plain = list(tail)
for h in HEREDOC.finditer(tail):
plain[h.start(3):h.end(3)] = "\0" * len(h.group(3))
return QUOTED.sub(lambda m: m.group() if m.group()[0] == "\\" or (keep and keep(m.group())) else "\0" * len(m.group()), "".join(plain))


def _flags(tail, names):
"""Yield the raw text after each occurrence of a flag in `names` (regex alternation), `--flag value` or `--flag=value`."""
for m in re.finditer(rf"(?:^|\s)(?:{names})(?:=|[ \t]+)", tail):
"""Yield the raw text after each occurrence of a flag in `names` (regex alternation), `--flag value` or `--flag=value`.
A flag-like word inside a quoted string (the title "Add -b flag") or a heredoc body is not a flag."""
for m in re.finditer(rf"(?:^|\s)(?:{names})(?:=|[ \t]+)", _plain(tail)):
yield tail[m.end():]


Expand Down Expand Up @@ -82,21 +93,30 @@ def _gh_body(tail, noun, cwd):
return None


def _rest_body(tail, cwd):
for rest in _flags(tail, r"-f|-F|--field|--raw-field"): # gh api -f body=TEXT, -f 'body=TEXT', -F body=@FILE
q = re.match(r"([\"'])body=", rest)
if q:
return _value(q.group(1) + rest[q.end():], cwd)
if rest.startswith("body="):
return _file(rest[5:], cwd, tail) if rest[5:].startswith("@") else _value(rest[5:], cwd)
def _rest_field(tail, cwd, key, literal=False):
"""The text of one field (`body`, `title`) a REST write sends, or None if it is absent or unreadable. gh sends `-f`/`--raw-field`
text as typed (`@jane` is a mention) and reads `-F`/`--field` `@FILE`; `literal` gives an unreadable `@FILE` as typed, not an error."""
for names, at_file in ((r"-f|--raw-field", False), (r"-F|--field", True)): # gh api -f body=TEXT, -f 'body=TEXT', -F body=@FILE
for rest in _flags(tail, names):
q = re.match(rf"([\"']){key}=", rest)
if q or rest.startswith(key + "="):
val = _value(q.group(1) + rest[q.end():] if q else rest[len(key) + 1:], cwd) # one shell word: more arguments may follow
if not (at_file and val and val.startswith("@")):
return val
try:
return _file(val, cwd, tail)
except (OSError, ValueError):
if literal:
return val
raise
for rest in _flags(tail, r"-d|--data|--data-raw|--data-binary"): # curl -d '{"body": ...}' or -d @FILE
raw = _value(rest, cwd)
raw = _file(raw, cwd, tail) if raw and (raw.startswith("@") or raw == "-") else raw
return json.loads(raw).get("body") if raw else None
return json.loads(raw).get(key) if raw else None
for rest in _flags(tail, r"--input"): # gh api --input FILE
name = _value(rest, cwd)
raw = _file(name, cwd, tail) if name else None
return json.loads(raw).get("body") if raw else None
return json.loads(raw).get(key) if raw else None
return None


Expand All @@ -116,7 +136,7 @@ def extract(tool_name, tool_input, cwd=""):
body = _gh_body(cmd[m.start():], noun, cwd)
elif (m := REST.search(cmd)):
kind = "pr" if m.group(1) == "pulls" and not m.group(2).endswith(("comments", "reviews")) else "message"
body = _rest_body(cmd[m.start():], cwd)
body = _rest_field(cmd[m.start():], cwd, "body")
else:
return None
except (OSError, ValueError, AttributeError): # unreadable file, non-JSON data: nothing to lint
Expand Down
Loading
Loading