@codyswann/lisa 2.163.4 → 2.163.5
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/codex/scripts/block-no-verify.sh +63 -9
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/hooks/block-no-verify.agy.sh +62 -13
- package/plugins/lisa/hooks/block-no-verify.sh +62 -10
- package/plugins/lisa-agy/hooks/block-no-verify.agy.sh +62 -13
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/hooks/block-no-verify.sh +62 -10
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/block-no-verify.sh +62 -10
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/hooks/block-no-verify.agy.sh +62 -13
- package/plugins/src/base/hooks/block-no-verify.sh +62 -10
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
# Lisa-managed Codex hook script (PreToolUse Bash).
|
|
3
3
|
# Blocks git commands that bypass verification hooks: the --no-verify long flag,
|
|
4
4
|
# HUSKY=0 / HUSKY_SKIP_HOOKS= (disables husky hooks), and core.hooksPath pointed
|
|
5
|
-
# at /dev/null or set empty (disables all git hooks).
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
5
|
+
# at /dev/null or set empty (disables all git hooks). Shell-token matching
|
|
6
|
+
# avoids false positives from issue bodies, heredocs, and commit-message prose
|
|
7
|
+
# while still catching quoted real argv values such as
|
|
8
|
+
# `git -c "core.hooksPath=/dev/null"`.
|
|
9
9
|
set -euo pipefail
|
|
10
10
|
|
|
11
11
|
input="$(cat 2>/dev/null || true)"
|
|
@@ -18,11 +18,65 @@ tool_name="$(printf '%s' "$input" | jq -r '.tool_name // empty' 2>/dev/null || t
|
|
|
18
18
|
command_str="$(printf '%s' "$input" | jq -r '.tool_input.command // empty' 2>/dev/null || true)"
|
|
19
19
|
[ -n "$command_str" ] || exit 0
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
command -v python3 >/dev/null 2>&1 || exit 0
|
|
22
|
+
|
|
23
|
+
if ! BLOCK_NO_VERIFY_COMMAND="$command_str" python3 - <<'PY'
|
|
24
|
+
import os
|
|
25
|
+
import re
|
|
26
|
+
import shlex
|
|
27
|
+
import sys
|
|
28
|
+
|
|
29
|
+
command = os.environ.get("BLOCK_NO_VERIFY_COMMAND", "")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def strip_heredocs(text: str) -> str:
|
|
33
|
+
lines = text.splitlines()
|
|
34
|
+
output = []
|
|
35
|
+
pending = []
|
|
36
|
+
marker_pattern = re.compile(
|
|
37
|
+
r"<<-?\s*(?:'([^']+)'|\"([^\"]+)\"|([A-Za-z_][A-Za-z0-9_]*))"
|
|
38
|
+
)
|
|
39
|
+
index = 0
|
|
40
|
+
while index < len(lines):
|
|
41
|
+
line = lines[index]
|
|
42
|
+
output.append(line)
|
|
43
|
+
pending.extend(
|
|
44
|
+
next(group for group in match.groups() if group)
|
|
45
|
+
for match in marker_pattern.finditer(line)
|
|
46
|
+
)
|
|
47
|
+
index += 1
|
|
48
|
+
while pending and index < len(lines):
|
|
49
|
+
if lines[index].strip() == pending[0]:
|
|
50
|
+
output.append(lines[index])
|
|
51
|
+
pending.pop(0)
|
|
52
|
+
index += 1
|
|
53
|
+
break
|
|
54
|
+
index += 1
|
|
55
|
+
return "\n".join(output)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
try:
|
|
59
|
+
tokens = shlex.split(strip_heredocs(command), posix=True)
|
|
60
|
+
except ValueError:
|
|
61
|
+
sys.exit(0)
|
|
62
|
+
|
|
63
|
+
normalized_tokens = [token.strip("();|&") for token in tokens]
|
|
64
|
+
|
|
65
|
+
for i, token in enumerate(normalized_tokens):
|
|
66
|
+
if token == "--no-verify":
|
|
67
|
+
sys.exit(1)
|
|
68
|
+
if token == "HUSKY=0" or token.startswith("HUSKY_SKIP_HOOKS="):
|
|
69
|
+
sys.exit(1)
|
|
70
|
+
if token.startswith("core.hooksPath="):
|
|
71
|
+
value = token.split("=", 1)[1]
|
|
72
|
+
if value in ("", "/dev/null"):
|
|
73
|
+
sys.exit(1)
|
|
74
|
+
if token == "core.hooksPath" and i + 1 < len(normalized_tokens) and normalized_tokens[i + 1] in ("", "/dev/null"):
|
|
75
|
+
sys.exit(1)
|
|
76
|
+
|
|
77
|
+
sys.exit(0)
|
|
78
|
+
PY
|
|
79
|
+
then
|
|
26
80
|
jq -n '{
|
|
27
81
|
"hookSpecificOutput": {
|
|
28
82
|
"hookEventName": "PreToolUse",
|
package/package.json
CHANGED
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"lodash": ">=4.18.1"
|
|
86
86
|
},
|
|
87
87
|
"name": "@codyswann/lisa",
|
|
88
|
-
"version": "2.163.
|
|
88
|
+
"version": "2.163.5",
|
|
89
89
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
90
90
|
"main": "dist/index.js",
|
|
91
91
|
"exports": {
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
# git quality gates (exact parity with the Claude block-no-verify.sh): the
|
|
4
4
|
# `--no-verify` long flag, `HUSKY=0`/`HUSKY_SKIP_HOOKS=` (disables husky hooks),
|
|
5
5
|
# and `core.hooksPath` pointed at /dev/null or set empty (disables all git
|
|
6
|
-
# hooks).
|
|
7
|
-
#
|
|
6
|
+
# hooks). Shell-token matching avoids false positives from issue bodies,
|
|
7
|
+
# heredocs, and commit-message prose while still catching quoted real argv
|
|
8
|
+
# values such as `git -c "core.hooksPath=/dev/null"`.
|
|
8
9
|
#
|
|
9
10
|
# agy protocol (distinct from the Claude block-no-verify.sh exit-code protocol):
|
|
10
11
|
# - stdin = JSON: { "toolCall": { "name": "run_command",
|
|
@@ -34,17 +35,65 @@ input="$(cat 2>/dev/null || true)"
|
|
|
34
35
|
command_str="$(printf '%s' "$input" | jq -r '.toolCall.args.CommandLine // empty' 2>/dev/null || true)"
|
|
35
36
|
[ -z "$command_str" ] && allow
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
command -v python3 >/dev/null 2>&1 || allow
|
|
39
|
+
|
|
40
|
+
if ! BLOCK_NO_VERIFY_COMMAND="$command_str" python3 - <<'PY'
|
|
41
|
+
import os
|
|
42
|
+
import re
|
|
43
|
+
import shlex
|
|
44
|
+
import sys
|
|
45
|
+
|
|
46
|
+
command = os.environ.get("BLOCK_NO_VERIFY_COMMAND", "")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def strip_heredocs(text: str) -> str:
|
|
50
|
+
lines = text.splitlines()
|
|
51
|
+
output = []
|
|
52
|
+
pending = []
|
|
53
|
+
marker_pattern = re.compile(
|
|
54
|
+
r"<<-?\s*(?:'([^']+)'|\"([^\"]+)\"|([A-Za-z_][A-Za-z0-9_]*))"
|
|
55
|
+
)
|
|
56
|
+
index = 0
|
|
57
|
+
while index < len(lines):
|
|
58
|
+
line = lines[index]
|
|
59
|
+
output.append(line)
|
|
60
|
+
pending.extend(
|
|
61
|
+
next(group for group in match.groups() if group)
|
|
62
|
+
for match in marker_pattern.finditer(line)
|
|
63
|
+
)
|
|
64
|
+
index += 1
|
|
65
|
+
while pending and index < len(lines):
|
|
66
|
+
if lines[index].strip() == pending[0]:
|
|
67
|
+
output.append(lines[index])
|
|
68
|
+
pending.pop(0)
|
|
69
|
+
index += 1
|
|
70
|
+
break
|
|
71
|
+
index += 1
|
|
72
|
+
return "\n".join(output)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
tokens = shlex.split(strip_heredocs(command), posix=True)
|
|
77
|
+
except ValueError:
|
|
78
|
+
sys.exit(0)
|
|
79
|
+
|
|
80
|
+
normalized_tokens = [token.strip("();|&") for token in tokens]
|
|
81
|
+
|
|
82
|
+
for i, token in enumerate(normalized_tokens):
|
|
83
|
+
if token == "--no-verify":
|
|
84
|
+
sys.exit(1)
|
|
85
|
+
if token == "HUSKY=0" or token.startswith("HUSKY_SKIP_HOOKS="):
|
|
86
|
+
sys.exit(1)
|
|
87
|
+
if token.startswith("core.hooksPath="):
|
|
88
|
+
value = token.split("=", 1)[1]
|
|
89
|
+
if value in ("", "/dev/null"):
|
|
90
|
+
sys.exit(1)
|
|
91
|
+
if token == "core.hooksPath" and i + 1 < len(normalized_tokens) and normalized_tokens[i + 1] in ("", "/dev/null"):
|
|
92
|
+
sys.exit(1)
|
|
93
|
+
|
|
94
|
+
sys.exit(0)
|
|
95
|
+
PY
|
|
96
|
+
then
|
|
48
97
|
deny
|
|
49
98
|
fi
|
|
50
99
|
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
# 2. HUSKY=0 / HUSKY_SKIP_HOOKS=... — disables husky-managed git hooks;
|
|
10
10
|
# 3. core.hooksPath pointed at /dev/null or set empty — disables ALL git hooks.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
12
|
+
# Shell-token matching avoids false positives from issue bodies, heredocs, and
|
|
13
|
+
# commit-message prose while still catching quoted real argv values such as
|
|
14
|
+
# `git -c "core.hooksPath=/dev/null"`.
|
|
14
15
|
#
|
|
15
16
|
# The short `-n` form is intentionally NOT matched (see block-no-verify.agy.sh):
|
|
16
17
|
# grep cannot distinguish a real -n option from -n in commit-message prose or an
|
|
@@ -29,14 +30,65 @@ if [ -z "$command_str" ]; then
|
|
|
29
30
|
exit 0
|
|
30
31
|
fi
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
command -v python3 >/dev/null 2>&1 || exit 0
|
|
34
|
+
|
|
35
|
+
if ! BLOCK_NO_VERIFY_COMMAND="$command_str" python3 - <<'PY'
|
|
36
|
+
import os
|
|
37
|
+
import re
|
|
38
|
+
import shlex
|
|
39
|
+
import sys
|
|
40
|
+
|
|
41
|
+
command = os.environ.get("BLOCK_NO_VERIFY_COMMAND", "")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def strip_heredocs(text: str) -> str:
|
|
45
|
+
lines = text.splitlines()
|
|
46
|
+
output = []
|
|
47
|
+
pending = []
|
|
48
|
+
marker_pattern = re.compile(
|
|
49
|
+
r"<<-?\s*(?:'([^']+)'|\"([^\"]+)\"|([A-Za-z_][A-Za-z0-9_]*))"
|
|
50
|
+
)
|
|
51
|
+
index = 0
|
|
52
|
+
while index < len(lines):
|
|
53
|
+
line = lines[index]
|
|
54
|
+
output.append(line)
|
|
55
|
+
pending.extend(
|
|
56
|
+
next(group for group in match.groups() if group)
|
|
57
|
+
for match in marker_pattern.finditer(line)
|
|
58
|
+
)
|
|
59
|
+
index += 1
|
|
60
|
+
while pending and index < len(lines):
|
|
61
|
+
if lines[index].strip() == pending[0]:
|
|
62
|
+
output.append(lines[index])
|
|
63
|
+
pending.pop(0)
|
|
64
|
+
index += 1
|
|
65
|
+
break
|
|
66
|
+
index += 1
|
|
67
|
+
return "\n".join(output)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
tokens = shlex.split(strip_heredocs(command), posix=True)
|
|
72
|
+
except ValueError:
|
|
73
|
+
sys.exit(0)
|
|
74
|
+
|
|
75
|
+
normalized_tokens = [token.strip("();|&") for token in tokens]
|
|
76
|
+
|
|
77
|
+
for i, token in enumerate(normalized_tokens):
|
|
78
|
+
if token == "--no-verify":
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
if token == "HUSKY=0" or token.startswith("HUSKY_SKIP_HOOKS="):
|
|
81
|
+
sys.exit(1)
|
|
82
|
+
if token.startswith("core.hooksPath="):
|
|
83
|
+
value = token.split("=", 1)[1]
|
|
84
|
+
if value in ("", "/dev/null"):
|
|
85
|
+
sys.exit(1)
|
|
86
|
+
if token == "core.hooksPath" and i + 1 < len(normalized_tokens) and normalized_tokens[i + 1] in ("", "/dev/null"):
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
|
|
89
|
+
sys.exit(0)
|
|
90
|
+
PY
|
|
91
|
+
then
|
|
40
92
|
cat >&2 <<'EOF'
|
|
41
93
|
Blocked: this command bypasses pre-commit/pre-push hooks (--no-verify, HUSKY=0,
|
|
42
94
|
or core.hooksPath disabling). Fix the underlying issue (lint error, failing
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
# git quality gates (exact parity with the Claude block-no-verify.sh): the
|
|
4
4
|
# `--no-verify` long flag, `HUSKY=0`/`HUSKY_SKIP_HOOKS=` (disables husky hooks),
|
|
5
5
|
# and `core.hooksPath` pointed at /dev/null or set empty (disables all git
|
|
6
|
-
# hooks).
|
|
7
|
-
#
|
|
6
|
+
# hooks). Shell-token matching avoids false positives from issue bodies,
|
|
7
|
+
# heredocs, and commit-message prose while still catching quoted real argv
|
|
8
|
+
# values such as `git -c "core.hooksPath=/dev/null"`.
|
|
8
9
|
#
|
|
9
10
|
# agy protocol (distinct from the Claude block-no-verify.sh exit-code protocol):
|
|
10
11
|
# - stdin = JSON: { "toolCall": { "name": "run_command",
|
|
@@ -34,17 +35,65 @@ input="$(cat 2>/dev/null || true)"
|
|
|
34
35
|
command_str="$(printf '%s' "$input" | jq -r '.toolCall.args.CommandLine // empty' 2>/dev/null || true)"
|
|
35
36
|
[ -z "$command_str" ] && allow
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
command -v python3 >/dev/null 2>&1 || allow
|
|
39
|
+
|
|
40
|
+
if ! BLOCK_NO_VERIFY_COMMAND="$command_str" python3 - <<'PY'
|
|
41
|
+
import os
|
|
42
|
+
import re
|
|
43
|
+
import shlex
|
|
44
|
+
import sys
|
|
45
|
+
|
|
46
|
+
command = os.environ.get("BLOCK_NO_VERIFY_COMMAND", "")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def strip_heredocs(text: str) -> str:
|
|
50
|
+
lines = text.splitlines()
|
|
51
|
+
output = []
|
|
52
|
+
pending = []
|
|
53
|
+
marker_pattern = re.compile(
|
|
54
|
+
r"<<-?\s*(?:'([^']+)'|\"([^\"]+)\"|([A-Za-z_][A-Za-z0-9_]*))"
|
|
55
|
+
)
|
|
56
|
+
index = 0
|
|
57
|
+
while index < len(lines):
|
|
58
|
+
line = lines[index]
|
|
59
|
+
output.append(line)
|
|
60
|
+
pending.extend(
|
|
61
|
+
next(group for group in match.groups() if group)
|
|
62
|
+
for match in marker_pattern.finditer(line)
|
|
63
|
+
)
|
|
64
|
+
index += 1
|
|
65
|
+
while pending and index < len(lines):
|
|
66
|
+
if lines[index].strip() == pending[0]:
|
|
67
|
+
output.append(lines[index])
|
|
68
|
+
pending.pop(0)
|
|
69
|
+
index += 1
|
|
70
|
+
break
|
|
71
|
+
index += 1
|
|
72
|
+
return "\n".join(output)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
tokens = shlex.split(strip_heredocs(command), posix=True)
|
|
77
|
+
except ValueError:
|
|
78
|
+
sys.exit(0)
|
|
79
|
+
|
|
80
|
+
normalized_tokens = [token.strip("();|&") for token in tokens]
|
|
81
|
+
|
|
82
|
+
for i, token in enumerate(normalized_tokens):
|
|
83
|
+
if token == "--no-verify":
|
|
84
|
+
sys.exit(1)
|
|
85
|
+
if token == "HUSKY=0" or token.startswith("HUSKY_SKIP_HOOKS="):
|
|
86
|
+
sys.exit(1)
|
|
87
|
+
if token.startswith("core.hooksPath="):
|
|
88
|
+
value = token.split("=", 1)[1]
|
|
89
|
+
if value in ("", "/dev/null"):
|
|
90
|
+
sys.exit(1)
|
|
91
|
+
if token == "core.hooksPath" and i + 1 < len(normalized_tokens) and normalized_tokens[i + 1] in ("", "/dev/null"):
|
|
92
|
+
sys.exit(1)
|
|
93
|
+
|
|
94
|
+
sys.exit(0)
|
|
95
|
+
PY
|
|
96
|
+
then
|
|
48
97
|
deny
|
|
49
98
|
fi
|
|
50
99
|
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
# 2. HUSKY=0 / HUSKY_SKIP_HOOKS=... — disables husky-managed git hooks;
|
|
10
10
|
# 3. core.hooksPath pointed at /dev/null or set empty — disables ALL git hooks.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
12
|
+
# Shell-token matching avoids false positives from issue bodies, heredocs, and
|
|
13
|
+
# commit-message prose while still catching quoted real argv values such as
|
|
14
|
+
# `git -c "core.hooksPath=/dev/null"`.
|
|
14
15
|
#
|
|
15
16
|
# The short `-n` form is intentionally NOT matched (see block-no-verify.agy.sh):
|
|
16
17
|
# grep cannot distinguish a real -n option from -n in commit-message prose or an
|
|
@@ -29,14 +30,65 @@ if [ -z "$command_str" ]; then
|
|
|
29
30
|
exit 0
|
|
30
31
|
fi
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
command -v python3 >/dev/null 2>&1 || exit 0
|
|
34
|
+
|
|
35
|
+
if ! BLOCK_NO_VERIFY_COMMAND="$command_str" python3 - <<'PY'
|
|
36
|
+
import os
|
|
37
|
+
import re
|
|
38
|
+
import shlex
|
|
39
|
+
import sys
|
|
40
|
+
|
|
41
|
+
command = os.environ.get("BLOCK_NO_VERIFY_COMMAND", "")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def strip_heredocs(text: str) -> str:
|
|
45
|
+
lines = text.splitlines()
|
|
46
|
+
output = []
|
|
47
|
+
pending = []
|
|
48
|
+
marker_pattern = re.compile(
|
|
49
|
+
r"<<-?\s*(?:'([^']+)'|\"([^\"]+)\"|([A-Za-z_][A-Za-z0-9_]*))"
|
|
50
|
+
)
|
|
51
|
+
index = 0
|
|
52
|
+
while index < len(lines):
|
|
53
|
+
line = lines[index]
|
|
54
|
+
output.append(line)
|
|
55
|
+
pending.extend(
|
|
56
|
+
next(group for group in match.groups() if group)
|
|
57
|
+
for match in marker_pattern.finditer(line)
|
|
58
|
+
)
|
|
59
|
+
index += 1
|
|
60
|
+
while pending and index < len(lines):
|
|
61
|
+
if lines[index].strip() == pending[0]:
|
|
62
|
+
output.append(lines[index])
|
|
63
|
+
pending.pop(0)
|
|
64
|
+
index += 1
|
|
65
|
+
break
|
|
66
|
+
index += 1
|
|
67
|
+
return "\n".join(output)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
tokens = shlex.split(strip_heredocs(command), posix=True)
|
|
72
|
+
except ValueError:
|
|
73
|
+
sys.exit(0)
|
|
74
|
+
|
|
75
|
+
normalized_tokens = [token.strip("();|&") for token in tokens]
|
|
76
|
+
|
|
77
|
+
for i, token in enumerate(normalized_tokens):
|
|
78
|
+
if token == "--no-verify":
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
if token == "HUSKY=0" or token.startswith("HUSKY_SKIP_HOOKS="):
|
|
81
|
+
sys.exit(1)
|
|
82
|
+
if token.startswith("core.hooksPath="):
|
|
83
|
+
value = token.split("=", 1)[1]
|
|
84
|
+
if value in ("", "/dev/null"):
|
|
85
|
+
sys.exit(1)
|
|
86
|
+
if token == "core.hooksPath" and i + 1 < len(normalized_tokens) and normalized_tokens[i + 1] in ("", "/dev/null"):
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
|
|
89
|
+
sys.exit(0)
|
|
90
|
+
PY
|
|
91
|
+
then
|
|
40
92
|
cat >&2 <<'EOF'
|
|
41
93
|
Blocked: this command bypasses pre-commit/pre-push hooks (--no-verify, HUSKY=0,
|
|
42
94
|
or core.hooksPath disabling). Fix the underlying issue (lint error, failing
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
# 2. HUSKY=0 / HUSKY_SKIP_HOOKS=... — disables husky-managed git hooks;
|
|
10
10
|
# 3. core.hooksPath pointed at /dev/null or set empty — disables ALL git hooks.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
12
|
+
# Shell-token matching avoids false positives from issue bodies, heredocs, and
|
|
13
|
+
# commit-message prose while still catching quoted real argv values such as
|
|
14
|
+
# `git -c "core.hooksPath=/dev/null"`.
|
|
14
15
|
#
|
|
15
16
|
# The short `-n` form is intentionally NOT matched (see block-no-verify.agy.sh):
|
|
16
17
|
# grep cannot distinguish a real -n option from -n in commit-message prose or an
|
|
@@ -29,14 +30,65 @@ if [ -z "$command_str" ]; then
|
|
|
29
30
|
exit 0
|
|
30
31
|
fi
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
command -v python3 >/dev/null 2>&1 || exit 0
|
|
34
|
+
|
|
35
|
+
if ! BLOCK_NO_VERIFY_COMMAND="$command_str" python3 - <<'PY'
|
|
36
|
+
import os
|
|
37
|
+
import re
|
|
38
|
+
import shlex
|
|
39
|
+
import sys
|
|
40
|
+
|
|
41
|
+
command = os.environ.get("BLOCK_NO_VERIFY_COMMAND", "")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def strip_heredocs(text: str) -> str:
|
|
45
|
+
lines = text.splitlines()
|
|
46
|
+
output = []
|
|
47
|
+
pending = []
|
|
48
|
+
marker_pattern = re.compile(
|
|
49
|
+
r"<<-?\s*(?:'([^']+)'|\"([^\"]+)\"|([A-Za-z_][A-Za-z0-9_]*))"
|
|
50
|
+
)
|
|
51
|
+
index = 0
|
|
52
|
+
while index < len(lines):
|
|
53
|
+
line = lines[index]
|
|
54
|
+
output.append(line)
|
|
55
|
+
pending.extend(
|
|
56
|
+
next(group for group in match.groups() if group)
|
|
57
|
+
for match in marker_pattern.finditer(line)
|
|
58
|
+
)
|
|
59
|
+
index += 1
|
|
60
|
+
while pending and index < len(lines):
|
|
61
|
+
if lines[index].strip() == pending[0]:
|
|
62
|
+
output.append(lines[index])
|
|
63
|
+
pending.pop(0)
|
|
64
|
+
index += 1
|
|
65
|
+
break
|
|
66
|
+
index += 1
|
|
67
|
+
return "\n".join(output)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
tokens = shlex.split(strip_heredocs(command), posix=True)
|
|
72
|
+
except ValueError:
|
|
73
|
+
sys.exit(0)
|
|
74
|
+
|
|
75
|
+
normalized_tokens = [token.strip("();|&") for token in tokens]
|
|
76
|
+
|
|
77
|
+
for i, token in enumerate(normalized_tokens):
|
|
78
|
+
if token == "--no-verify":
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
if token == "HUSKY=0" or token.startswith("HUSKY_SKIP_HOOKS="):
|
|
81
|
+
sys.exit(1)
|
|
82
|
+
if token.startswith("core.hooksPath="):
|
|
83
|
+
value = token.split("=", 1)[1]
|
|
84
|
+
if value in ("", "/dev/null"):
|
|
85
|
+
sys.exit(1)
|
|
86
|
+
if token == "core.hooksPath" and i + 1 < len(normalized_tokens) and normalized_tokens[i + 1] in ("", "/dev/null"):
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
|
|
89
|
+
sys.exit(0)
|
|
90
|
+
PY
|
|
91
|
+
then
|
|
40
92
|
cat >&2 <<'EOF'
|
|
41
93
|
Blocked: this command bypasses pre-commit/pre-push hooks (--no-verify, HUSKY=0,
|
|
42
94
|
or core.hooksPath disabling). Fix the underlying issue (lint error, failing
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.163.
|
|
3
|
+
"version": "2.163.5",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.163.
|
|
3
|
+
"version": "2.163.5",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.163.
|
|
3
|
+
"version": "2.163.5",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.163.
|
|
3
|
+
"version": "2.163.5",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.163.
|
|
3
|
+
"version": "2.163.5",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
# git quality gates (exact parity with the Claude block-no-verify.sh): the
|
|
4
4
|
# `--no-verify` long flag, `HUSKY=0`/`HUSKY_SKIP_HOOKS=` (disables husky hooks),
|
|
5
5
|
# and `core.hooksPath` pointed at /dev/null or set empty (disables all git
|
|
6
|
-
# hooks).
|
|
7
|
-
#
|
|
6
|
+
# hooks). Shell-token matching avoids false positives from issue bodies,
|
|
7
|
+
# heredocs, and commit-message prose while still catching quoted real argv
|
|
8
|
+
# values such as `git -c "core.hooksPath=/dev/null"`.
|
|
8
9
|
#
|
|
9
10
|
# agy protocol (distinct from the Claude block-no-verify.sh exit-code protocol):
|
|
10
11
|
# - stdin = JSON: { "toolCall": { "name": "run_command",
|
|
@@ -34,17 +35,65 @@ input="$(cat 2>/dev/null || true)"
|
|
|
34
35
|
command_str="$(printf '%s' "$input" | jq -r '.toolCall.args.CommandLine // empty' 2>/dev/null || true)"
|
|
35
36
|
[ -z "$command_str" ] && allow
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
38
|
+
command -v python3 >/dev/null 2>&1 || allow
|
|
39
|
+
|
|
40
|
+
if ! BLOCK_NO_VERIFY_COMMAND="$command_str" python3 - <<'PY'
|
|
41
|
+
import os
|
|
42
|
+
import re
|
|
43
|
+
import shlex
|
|
44
|
+
import sys
|
|
45
|
+
|
|
46
|
+
command = os.environ.get("BLOCK_NO_VERIFY_COMMAND", "")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def strip_heredocs(text: str) -> str:
|
|
50
|
+
lines = text.splitlines()
|
|
51
|
+
output = []
|
|
52
|
+
pending = []
|
|
53
|
+
marker_pattern = re.compile(
|
|
54
|
+
r"<<-?\s*(?:'([^']+)'|\"([^\"]+)\"|([A-Za-z_][A-Za-z0-9_]*))"
|
|
55
|
+
)
|
|
56
|
+
index = 0
|
|
57
|
+
while index < len(lines):
|
|
58
|
+
line = lines[index]
|
|
59
|
+
output.append(line)
|
|
60
|
+
pending.extend(
|
|
61
|
+
next(group for group in match.groups() if group)
|
|
62
|
+
for match in marker_pattern.finditer(line)
|
|
63
|
+
)
|
|
64
|
+
index += 1
|
|
65
|
+
while pending and index < len(lines):
|
|
66
|
+
if lines[index].strip() == pending[0]:
|
|
67
|
+
output.append(lines[index])
|
|
68
|
+
pending.pop(0)
|
|
69
|
+
index += 1
|
|
70
|
+
break
|
|
71
|
+
index += 1
|
|
72
|
+
return "\n".join(output)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
tokens = shlex.split(strip_heredocs(command), posix=True)
|
|
77
|
+
except ValueError:
|
|
78
|
+
sys.exit(0)
|
|
79
|
+
|
|
80
|
+
normalized_tokens = [token.strip("();|&") for token in tokens]
|
|
81
|
+
|
|
82
|
+
for i, token in enumerate(normalized_tokens):
|
|
83
|
+
if token == "--no-verify":
|
|
84
|
+
sys.exit(1)
|
|
85
|
+
if token == "HUSKY=0" or token.startswith("HUSKY_SKIP_HOOKS="):
|
|
86
|
+
sys.exit(1)
|
|
87
|
+
if token.startswith("core.hooksPath="):
|
|
88
|
+
value = token.split("=", 1)[1]
|
|
89
|
+
if value in ("", "/dev/null"):
|
|
90
|
+
sys.exit(1)
|
|
91
|
+
if token == "core.hooksPath" and i + 1 < len(normalized_tokens) and normalized_tokens[i + 1] in ("", "/dev/null"):
|
|
92
|
+
sys.exit(1)
|
|
93
|
+
|
|
94
|
+
sys.exit(0)
|
|
95
|
+
PY
|
|
96
|
+
then
|
|
48
97
|
deny
|
|
49
98
|
fi
|
|
50
99
|
|
|
@@ -9,8 +9,9 @@
|
|
|
9
9
|
# 2. HUSKY=0 / HUSKY_SKIP_HOOKS=... — disables husky-managed git hooks;
|
|
10
10
|
# 3. core.hooksPath pointed at /dev/null or set empty — disables ALL git hooks.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
12
|
+
# Shell-token matching avoids false positives from issue bodies, heredocs, and
|
|
13
|
+
# commit-message prose while still catching quoted real argv values such as
|
|
14
|
+
# `git -c "core.hooksPath=/dev/null"`.
|
|
14
15
|
#
|
|
15
16
|
# The short `-n` form is intentionally NOT matched (see block-no-verify.agy.sh):
|
|
16
17
|
# grep cannot distinguish a real -n option from -n in commit-message prose or an
|
|
@@ -29,14 +30,65 @@ if [ -z "$command_str" ]; then
|
|
|
29
30
|
exit 0
|
|
30
31
|
fi
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
command -v python3 >/dev/null 2>&1 || exit 0
|
|
34
|
+
|
|
35
|
+
if ! BLOCK_NO_VERIFY_COMMAND="$command_str" python3 - <<'PY'
|
|
36
|
+
import os
|
|
37
|
+
import re
|
|
38
|
+
import shlex
|
|
39
|
+
import sys
|
|
40
|
+
|
|
41
|
+
command = os.environ.get("BLOCK_NO_VERIFY_COMMAND", "")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def strip_heredocs(text: str) -> str:
|
|
45
|
+
lines = text.splitlines()
|
|
46
|
+
output = []
|
|
47
|
+
pending = []
|
|
48
|
+
marker_pattern = re.compile(
|
|
49
|
+
r"<<-?\s*(?:'([^']+)'|\"([^\"]+)\"|([A-Za-z_][A-Za-z0-9_]*))"
|
|
50
|
+
)
|
|
51
|
+
index = 0
|
|
52
|
+
while index < len(lines):
|
|
53
|
+
line = lines[index]
|
|
54
|
+
output.append(line)
|
|
55
|
+
pending.extend(
|
|
56
|
+
next(group for group in match.groups() if group)
|
|
57
|
+
for match in marker_pattern.finditer(line)
|
|
58
|
+
)
|
|
59
|
+
index += 1
|
|
60
|
+
while pending and index < len(lines):
|
|
61
|
+
if lines[index].strip() == pending[0]:
|
|
62
|
+
output.append(lines[index])
|
|
63
|
+
pending.pop(0)
|
|
64
|
+
index += 1
|
|
65
|
+
break
|
|
66
|
+
index += 1
|
|
67
|
+
return "\n".join(output)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
tokens = shlex.split(strip_heredocs(command), posix=True)
|
|
72
|
+
except ValueError:
|
|
73
|
+
sys.exit(0)
|
|
74
|
+
|
|
75
|
+
normalized_tokens = [token.strip("();|&") for token in tokens]
|
|
76
|
+
|
|
77
|
+
for i, token in enumerate(normalized_tokens):
|
|
78
|
+
if token == "--no-verify":
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
if token == "HUSKY=0" or token.startswith("HUSKY_SKIP_HOOKS="):
|
|
81
|
+
sys.exit(1)
|
|
82
|
+
if token.startswith("core.hooksPath="):
|
|
83
|
+
value = token.split("=", 1)[1]
|
|
84
|
+
if value in ("", "/dev/null"):
|
|
85
|
+
sys.exit(1)
|
|
86
|
+
if token == "core.hooksPath" and i + 1 < len(normalized_tokens) and normalized_tokens[i + 1] in ("", "/dev/null"):
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
|
|
89
|
+
sys.exit(0)
|
|
90
|
+
PY
|
|
91
|
+
then
|
|
40
92
|
cat >&2 <<'EOF'
|
|
41
93
|
Blocked: this command bypasses pre-commit/pre-push hooks (--no-verify, HUSKY=0,
|
|
42
94
|
or core.hooksPath disabling). Fix the underlying issue (lint error, failing
|