@codyswann/lisa 2.341.2 → 2.341.4

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.
Files changed (85) hide show
  1. package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +14 -1
  2. package/all/copy-overwrite/scripts/lisa-hooks/block-instruction-file-edits.sh +47 -7
  3. package/all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh +49 -5
  4. package/all/copy-overwrite/scripts/lisa-hooks/block-shell-json-parsing.sh +20 -1
  5. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  6. package/dist/core/upstream-evidence-manifest.js +12 -10
  7. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  8. package/package.json +3 -1
  9. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  10. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  11. package/plugins/lisa/.codex-plugin/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  12. package/plugins/lisa/.codex-plugin/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  13. package/plugins/lisa/hooks/block-instruction-file-edits.sh +47 -7
  14. package/plugins/lisa/hooks/block-no-verify.sh +49 -5
  15. package/plugins/lisa/hooks/block-shell-json-parsing.sh +20 -1
  16. package/plugins/lisa/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  17. package/plugins/lisa/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  18. package/plugins/lisa-agy/hooks/block-instruction-file-edits.sh +47 -7
  19. package/plugins/lisa-agy/hooks/block-shell-json-parsing.sh +20 -1
  20. package/plugins/lisa-agy/plugin.json +1 -1
  21. package/plugins/lisa-agy/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  22. package/plugins/lisa-agy/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  23. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  25. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  26. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-copilot/hooks/block-instruction-file-edits.sh +47 -7
  30. package/plugins/lisa-copilot/hooks/block-no-verify.sh +49 -5
  31. package/plugins/lisa-copilot/hooks/block-shell-json-parsing.sh +20 -1
  32. package/plugins/lisa-copilot/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  33. package/plugins/lisa-copilot/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  34. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-cursor/hooks/block-instruction-file-edits.sh +47 -7
  36. package/plugins/lisa-cursor/hooks/block-no-verify.sh +49 -5
  37. package/plugins/lisa-cursor/hooks/block-shell-json-parsing.sh +20 -1
  38. package/plugins/lisa-cursor/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  39. package/plugins/lisa-cursor/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  40. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-expo-agy/plugin.json +1 -1
  43. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  48. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  53. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  58. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  63. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-rails-agy/plugin.json +1 -1
  68. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  72. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  73. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  77. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  78. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  80. package/plugins/src/base/hooks/block-instruction-file-edits.sh +47 -7
  81. package/plugins/src/base/hooks/block-no-verify.sh +49 -5
  82. package/plugins/src/base/hooks/block-shell-json-parsing.sh +20 -1
  83. package/plugins/src/base/skills/lisa-parity-sentry-sdk-setup/SKILL.md +2 -2
  84. package/plugins/src/base/skills/lisa-parity-sentry-seer/SKILL.md +2 -2
  85. package/scripts/lisa-enforcement-fallback.sh +14 -1
@@ -88,7 +88,20 @@ for guard in block-no-verify parity-safety-net block-shell-json-parsing \
88
88
  # fail-open this file exists to close.
89
89
  printf '%s' "$payload" | bash "$script"
90
90
  guard_status=$?
91
- if [ "$guard_status" -gt "$status" ]; then
91
+ # 2 is the ONLY status Claude Code treats as a refusal. Every other non-zero
92
+ # is a non-blocking error: it is surfaced, and the tool call proceeds anyway.
93
+ # So the aggregate cannot be the numerically largest status — under `-gt`, a
94
+ # guard erroring with 3, or dying on a missing interpreter with 127,
95
+ # outranks another guard's 2 and silently downgrades a refusal into a
96
+ # warning. That is the precise fail-open this file exists to close,
97
+ # reintroduced one layer up.
98
+ #
99
+ # 2 therefore dominates and is sticky; a lesser non-zero is only carried when
100
+ # no guard has refused, so a genuine error is still reported when nothing
101
+ # blocked.
102
+ if [ "$guard_status" -eq 2 ]; then
103
+ status=2
104
+ elif [ "$guard_status" -ne 0 ] && [ "$status" -ne 2 ]; then
92
105
  status="$guard_status"
93
106
  fi
94
107
  done
@@ -42,12 +42,48 @@ fi
42
42
  tool_name="$(printf '%s' "$input" | jq -r '.tool_name // empty')"
43
43
  [ -n "$tool_name" ] || exit 0
44
44
 
45
- # Lisa's own bounded bridges write marked regions. A payload carrying a marker
46
- # is replacing a delimited block, not appending prose, so it cannot be the
47
- # unbounded growth this guard exists to stop.
48
- if printf '%s' "$input" | grep -q '<!-- LISA_'; then
49
- exit 0
50
- fi
45
+ # Lisa's own bounded bridges write marked regions the agy project-learnings
46
+ # bridge and cross-pollinate's rule section. The premise of their exemption, as
47
+ # originally stated, is that they "replace in place and cannot grow the file".
48
+ # This enforces that premise rather than trusting it.
49
+ #
50
+ # Both sides have to be a marked region and nothing else:
51
+ #
52
+ # - old_string bounded proves the region really is on disk. Scanning the whole
53
+ # payload was trivially forgeable — any caller could put `<!-- LISA_` in the
54
+ # content it was WRITING and walk past the guard.
55
+ # - new_string bounded is what makes it a replacement rather than an append.
56
+ # old_string alone does not authorize anything: a caller can read a genuine
57
+ # marked region, echo it back verbatim, and still smuggle unbounded prose in
58
+ # after the closing marker. Requiring the written text to be exactly one
59
+ # marked region — whitespace aside — leaves nowhere to put it.
60
+ #
61
+ # Every edit in a MultiEdit must qualify; one unbounded edit taints the batch.
62
+ # Write is absent by construction: it has no old_string and clobbers the whole
63
+ # file, which is precisely the unbounded case.
64
+ case "$tool_name" in
65
+ Edit | MultiEdit)
66
+ if printf '%s' "$input" |
67
+ jq -e '
68
+ # Exactly ONE marked region and nothing else. The inner
69
+ # `(?!<!-- LISA_)` is what makes it one: a plain `[\s\S]*` anchors only
70
+ # the FIRST opening marker and the LAST closing marker, so
71
+ # `region + prose + region` satisfies it and the prose between the two
72
+ # regions rides along outside any marked block.
73
+ def bounded:
74
+ type == "string"
75
+ and test("^\\s*<!-- LISA_[A-Z_]+ -->(?:(?!<!-- LISA_)[\\s\\S])*<!-- LISA_[A-Z_]+ -->\\s*$");
76
+ def replacement_pairs:
77
+ if .tool_input.edits? then [.tool_input.edits[]?]
78
+ else [.tool_input] end;
79
+ replacement_pairs
80
+ | length > 0
81
+ and all(.[]; (.old_string | bounded) and (.new_string | bounded))
82
+ ' >/dev/null 2>&1; then
83
+ exit 0
84
+ fi
85
+ ;;
86
+ esac
51
87
 
52
88
  # Basename match, case-insensitively: `agents.md` and `AGENTS.md` are the same
53
89
  # file on the macOS checkouts this fleet runs on.
@@ -130,9 +166,13 @@ EOF
130
166
  # Write signatures only. A bare mention (`cat AGENTS.md`, `rg x AGENTS.md`)
131
167
  # is a read and must stay allowed — the filename has to appear as the target
132
168
  # of a redirection, a tee, or an in-place sed.
169
+ # `>>?\|?` covers `>`, `>>`, and the noclobber override `>|`. The bare-`>`
170
+ # branch already catches explicit fd forms such as `1>` / `2>>` because the
171
+ # pattern is unanchored and matches the `>` inside them; `>|` was the real
172
+ # gap, since `|` is excluded by the target class and so terminated the match.
133
173
  write_target='[^ |;&]*(agents|claude|copilot-instructions)\.md'
134
174
  if printf '%s' "$command_str" |
135
- grep -Eqi ">>?[[:space:]]*['\"]?$write_target|tee([[:space:]]+-[a-z]+)*[[:space:]]+['\"]?$write_target|sed[[:space:]]+[^|;&]*-i[^|;&]*$write_target"; then
175
+ grep -Eqi ">>?\|?[[:space:]]*['\"]?$write_target|tee([[:space:]]+-[a-z]+)*[[:space:]]+['\"]?$write_target|sed[[:space:]]+[^|;&]*-i[^|;&]*$write_target"; then
136
176
  refuse "$(printf '%s' "$command_str" |
137
177
  grep -Eoi "$write_target" | head -1)"
138
178
  fi
@@ -97,17 +97,61 @@ except ValueError:
97
97
 
98
98
  normalized_tokens = [token.strip("();|&") for token in tokens]
99
99
 
100
+ # The only relocations that keep a repo's own hooks in play. `.husky` is the
101
+ # husky convention this fleet runs; `.githooks` is the common hand-rolled one.
102
+ # Anything else — including "" and /dev/null, which are simply the two most
103
+ # obvious members of the blocked set rather than special cases — is refused.
104
+ PERMITTED_HOOKS_PATHS = {".husky", ".githooks"}
105
+
106
+
107
+ def is_permitted_hooks_path(value):
108
+ """Whether a core.hooksPath value relocates hooks rather than disabling them.
109
+
110
+ Args:
111
+ value: The raw core.hooksPath value as it appeared on the command line.
112
+
113
+ Returns:
114
+ True if the path is an established in-repo hooks directory.
115
+ """
116
+ cleaned = value.strip().strip("'\"")
117
+ if cleaned.startswith("./"):
118
+ cleaned = cleaned[2:]
119
+ return cleaned.rstrip("/") in PERMITTED_HOOKS_PATHS
120
+
100
121
  for i, token in enumerate(normalized_tokens):
101
122
  if token == "--no-verify":
102
123
  sys.exit(1)
103
124
  if token == "HUSKY=0" or token.startswith("HUSKY_SKIP_HOOKS="):
104
125
  sys.exit(1)
105
- if token.startswith("core.hooksPath="):
106
- value = token.split("=", 1)[1]
107
- if value in ("", "/dev/null"):
126
+ # Allowlist the destinations, do not denylist the disabling ones.
127
+ #
128
+ # This used to block only "" and /dev/null. But hooks are disabled just as
129
+ # completely by pointing hooksPath at any directory that happens to contain
130
+ # none — `-c core.hooksPath=/tmp/empty` bypassed every hook while reading as
131
+ # an ordinary path — so a denylist of "obviously disabling" values can
132
+ # always be stepped around by naming a third thing. The set of paths that
133
+ # DISABLE hooks is unbounded; the set that legitimately relocates them is
134
+ # tiny and known, so the allowlist is the only side that can be enumerated.
135
+ #
136
+ # Matched case-insensitively because git config variable names are:
137
+ # `CORE.HOOKSPATH=/x` and `core.hookspath=/x` are the same setting to git,
138
+ # so a case-sensitive check is bypassed by holding down shift.
139
+ lowered = token.lower()
140
+ if lowered.startswith("core.hookspath="):
141
+ if not is_permitted_hooks_path(token.split("=", 1)[1]):
142
+ sys.exit(1)
143
+ if lowered == "core.hookspath" and i + 1 < len(normalized_tokens):
144
+ if not is_permitted_hooks_path(normalized_tokens[i + 1]):
145
+ sys.exit(1)
146
+ # `git --config-env=core.hooksPath=SOMEVAR` sets the same config, reading
147
+ # the value out of the named environment variable. The path therefore is
148
+ # not in the command at all, so there is nothing to allowlist against —
149
+ # SOMEVAR can hold anything by the time git reads it. Any core.hooksPath
150
+ # routed through --config-env is refused outright.
151
+ if lowered.startswith("--config-env="):
152
+ spec = token.split("=", 1)[1]
153
+ if spec.split("=", 1)[0].strip().lower() == "core.hookspath":
108
154
  sys.exit(1)
109
- if token == "core.hooksPath" and i + 1 < len(normalized_tokens) and normalized_tokens[i + 1] in ("", "/dev/null"):
110
- sys.exit(1)
111
155
 
112
156
  sys.exit(0)
113
157
  PY
@@ -24,6 +24,25 @@ set -euo pipefail
24
24
 
25
25
  input="$(cat)"
26
26
 
27
+ # Probe the interpreters before the first use. Under `set -euo pipefail` an
28
+ # absent jq does not merely skip the parse — the assignment below dies with
29
+ # 127, and 127 is not a refusal, so the guard vanishes and the command runs.
30
+ # Worse, that 127 used to outrank a sibling guard's 2 in
31
+ # lisa-enforcement-fallback.sh, taking a real refusal down with it.
32
+ #
33
+ # Degrading to "allow" stays right: a hook that cannot parse its input cannot
34
+ # tell a bypass from an ordinary command, and failing closed would block every
35
+ # Bash call on a machine missing an interpreter. Doing it QUIETLY is what is
36
+ # wrong — a guard that is silently absent reads exactly like a guard that is
37
+ # passing. Mirrors block-no-verify.sh, which already had this.
38
+ for required in jq python3; do
39
+ if ! command -v "$required" >/dev/null 2>&1; then
40
+ printf 'block-shell-json-parsing: %s not found; JSON-parsing protection is NOT active\n' \
41
+ "$required" >&2
42
+ exit 0
43
+ fi
44
+ done
45
+
27
46
  tool_name="$(printf '%s' "$input" | jq -r '.tool_name // empty')"
28
47
  if [ "$tool_name" != "Bash" ]; then
29
48
  exit 0
@@ -40,7 +59,7 @@ case "$command_str" in
40
59
  *) exit 0 ;;
41
60
  esac
42
61
 
43
- command -v python3 >/dev/null 2>&1 || exit 0
62
+ # python3 is probed with jq at the top now, announced rather than silent.
44
63
 
45
64
  if ! BLOCK_SHELL_JSON_COMMAND="$command_str" python3 - <<'PY'
46
65
  import os
@@ -1 +1 @@
1
- {"version":3,"file":"upstream-evidence-manifest.d.ts","sourceRoot":"","sources":["../../src/core/upstream-evidence-manifest.ts"],"names":[],"mappings":"AACA,iFAAiF;AACjF,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwqEpE,CAAC;AAEL,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAgvNjE,CAAC;AAEL,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAk6I/D,CAAC"}
1
+ {"version":3,"file":"upstream-evidence-manifest.d.ts","sourceRoot":"","sources":["../../src/core/upstream-evidence-manifest.ts"],"names":[],"mappings":"AACA,iFAAiF;AACjF,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAwqEpE,CAAC;AAEL,4EAA4E;AAC5E,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAkvNjE,CAAC;AAEL,sFAAsF;AACtF,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAk6I/D,CAAC"}
@@ -3,11 +3,11 @@
3
3
  export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
4
4
  "all/copy-contents/.gitattributes": "9d3831007e681186a3673e1037ef3fc82980cab2fc04e27c0868e562912c9e9f",
5
5
  "all/copy-contents/gitignore": "2dbf7fd2f2020fc7824c432342002d9ca3ebb57b2872e761b14e942b23479a11",
6
- "all/copy-overwrite/scripts/lisa-enforcement-fallback.sh": "d7d88e44763694bed5eae998cd3663922c957e49f9f9621d9201f0417a4128ad",
6
+ "all/copy-overwrite/scripts/lisa-enforcement-fallback.sh": "1bec5f3c284b3febdc471487ee6a23ffb72bd4e7b293f9e26b0188f32318c722",
7
7
  "all/copy-overwrite/scripts/lisa-floor-collisions.mjs": "a612f172282d13ba9318fe5e03689d7c6ff42a0122d0c9d5d39051e1967b93dc",
8
- "all/copy-overwrite/scripts/lisa-hooks/block-instruction-file-edits.sh": "8996e0bcbf1db085a5d99734e797c91f5025997bd967bc374efff8348dac14c2",
9
- "all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh": "a6ed91576efebb6ba40cfa4e9d8a3e8566314909210ae8d5860be62a3feb4cff",
10
- "all/copy-overwrite/scripts/lisa-hooks/block-shell-json-parsing.sh": "3b5f074f3ab5708030af507eea962389f3b067c5dbdc76580bd9e44d3ac6c603",
8
+ "all/copy-overwrite/scripts/lisa-hooks/block-instruction-file-edits.sh": "850cfc23852eb752114ae1e938a1c7bcf34bc50c85d3aaca0c02311cc8c0ef70",
9
+ "all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh": "33e2bd341eb992036059b0c4606db35a218adcfeca7e44d174fedf8ebdff29d2",
10
+ "all/copy-overwrite/scripts/lisa-hooks/block-shell-json-parsing.sh": "1934a15e154fda3c2a40979a5cd6225661b14fe7bc77328a69ce499bea85dba7",
11
11
  "all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh": "062c69eea85157f1e941ec3626d8912aa9f182af6ccdbe19687588a6074db5ce",
12
12
  "all/copy-overwrite/scripts/lisa-hooks/sonar-secrets.sh": "bf4132e49ba18e2f7e941520c299c15aeeacfd220e489f3d2eb8397f2048157b",
13
13
  "all/copy-overwrite/scripts/lisa-work-item.mjs": "6a8be8577242588f14ab52b25b2a22b6def53aefa9513b4d3d7c49f4d8027079",
@@ -296,11 +296,11 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
296
296
  "plugins/src/base/commands/verify.md": "ffbc553ec86e77845da72b5b0eb0dbb2b5a93b781ac8a7dbb2ef0f31f38f7b96",
297
297
  "plugins/src/base/commands/wiki/install.md": "51392cf053c17edd549bfbaba5d19ce669dc79021aafa7cfa100324ad38de11f",
298
298
  "plugins/src/base/hooks/block-instruction-file-edits.agy.sh": "aa249cae53caeb3e0fb6d6af114e2756084f45a2896332fb063a9f20e4902125",
299
- "plugins/src/base/hooks/block-instruction-file-edits.sh": "8996e0bcbf1db085a5d99734e797c91f5025997bd967bc374efff8348dac14c2",
299
+ "plugins/src/base/hooks/block-instruction-file-edits.sh": "850cfc23852eb752114ae1e938a1c7bcf34bc50c85d3aaca0c02311cc8c0ef70",
300
300
  "plugins/src/base/hooks/block-no-verify.agy.sh": "1a36c841b6339a2c664938d65c5a4542f97d05f584e467de448bb72ac6bdba55",
301
- "plugins/src/base/hooks/block-no-verify.sh": "a6ed91576efebb6ba40cfa4e9d8a3e8566314909210ae8d5860be62a3feb4cff",
301
+ "plugins/src/base/hooks/block-no-verify.sh": "33e2bd341eb992036059b0c4606db35a218adcfeca7e44d174fedf8ebdff29d2",
302
302
  "plugins/src/base/hooks/block-shell-json-parsing.agy.sh": "dc688efe382e7b8fe6f6c88bb0fde851527128cae778599559f23a93f1c9ec86",
303
- "plugins/src/base/hooks/block-shell-json-parsing.sh": "3b5f074f3ab5708030af507eea962389f3b067c5dbdc76580bd9e44d3ac6c603",
303
+ "plugins/src/base/hooks/block-shell-json-parsing.sh": "1934a15e154fda3c2a40979a5cd6225661b14fe7bc77328a69ce499bea85dba7",
304
304
  "plugins/src/base/hooks/cleanup-stale-worktrees.sh": "c9b2fcca1b34d6f636b5289ece11b254cbb8ee2c2bac5c2e426b6f4dcfa972f2",
305
305
  "plugins/src/base/hooks/debug-hook.sh": "50124ffc72d7914553b0ed259882f2202643cdccf238380675ac1ff6d8d27d05",
306
306
  "plugins/src/base/hooks/enforce-team-first.sh": "104922ba5912b797bf9ce15881dcef76916ea1782ac1e669151265b7db9fb263",
@@ -516,8 +516,8 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
516
516
  "plugins/src/base/skills/lisa-parity-code-simplifier/SKILL.md": "c721ae772e73abff633c43d93267066afac188e911a77322fbb102db673849d7",
517
517
  "plugins/src/base/skills/lisa-parity-coderabbit/SKILL.md": "ae882837d43741293d1b639c4516331fa6124fa1f5da234a74ecb31c5d7e52cd",
518
518
  "plugins/src/base/skills/lisa-parity-safety-net-rules/SKILL.md": "8757ea8c83e9acaad1af59f7b46d5ac7efaba61da76f9df3fc94b258f9a16b2b",
519
- "plugins/src/base/skills/lisa-parity-sentry-sdk-setup/SKILL.md": "25357629d6674c35e53279d4b20b62f1b76c3bcd0f724eee99593425365dd0d5",
520
- "plugins/src/base/skills/lisa-parity-sentry-seer/SKILL.md": "583a288ef991ccbfb38ac3319b33bf9e8a158cb90fbc64a61993f51ac70ca657",
519
+ "plugins/src/base/skills/lisa-parity-sentry-sdk-setup/SKILL.md": "610890385568ae097b2a48c9d20e42104a1bf5a3ba06223a89086ef385542e3b",
520
+ "plugins/src/base/skills/lisa-parity-sentry-seer/SKILL.md": "d060d3171529cc228368e640d0ab813a79ec18440921602e7c720d53fdcabb67",
521
521
  "plugins/src/base/skills/lisa-parity-skill-creator/SKILL.md": "616e0493f75fe92c18137548d7c86a91a9b04d9844ca76fa3f14156e3e7814e5",
522
522
  "plugins/src/base/skills/lisa-performance-review/SKILL.md": "351542c256e54940e6d672a70606b8414425c6435ae6f026841bcc02f9fce9c4",
523
523
  "plugins/src/base/skills/lisa-persist-learning/SKILL.md": "41ffd8a415c6b1b98952061760e54837f3d6e6ea046e4d1c122dd53878af84de",
@@ -1012,7 +1012,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
1012
1012
  "scripts/lib/reusable-workflow-contract.d.mts": "791f01b55dd7a6b5d9a5f4cb9c44167caa146c2fc3c31a2ae4c2d8a350adc2f1",
1013
1013
  "scripts/lib/reusable-workflow-contract.mjs": "134ee2a327290f066f1eb318b5ed53c711557c3e10ed462c00ff5c97cfb20863",
1014
1014
  "scripts/lisa-commit-and-pr-local.sh": "605409c3ce6ec38ad3275604291a1ceae98f7807a605654263bc14f811c03903",
1015
- "scripts/lisa-enforcement-fallback.sh": "d7d88e44763694bed5eae998cd3663922c957e49f9f9621d9201f0417a4128ad",
1015
+ "scripts/lisa-enforcement-fallback.sh": "1bec5f3c284b3febdc471487ee6a23ffb72bd4e7b293f9e26b0188f32318c722",
1016
1016
  "scripts/lisa-github-environments.sh": "0a76e92f108519abaf3e29991299ec3b0db20ea533e69e6d2a53d802dba9c370",
1017
1017
  "scripts/lisa-github-repo-settings.sh": "4afbccdfb08c62ba13afee42ec8561a28facf87c61f6f4b80000115328364d54",
1018
1018
  "scripts/lisa-github-repo-setup.sh": "dc2f1c9d718aa34ba57161120d9319b5f78fe6b0b496d8e3c77226a08795aa36",
@@ -7329,6 +7329,7 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7329
7329
  "tests/unit/hooks/block-instruction-file-edits.test.ts": true,
7330
7330
  "tests/unit/hooks/block-no-verify-missing-jq.test.ts": true,
7331
7331
  "tests/unit/hooks/block-no-verify.test.ts": true,
7332
+ "tests/unit/hooks/block-shell-json-parsing-missing-deps.test.ts": true,
7332
7333
  "tests/unit/hooks/block-shell-json-parsing.test.ts": true,
7333
7334
  "tests/unit/hooks/blocking-hook-exit.test.ts": true,
7334
7335
  "tests/unit/hooks/cleanup-stale-worktrees.test.ts": true,
@@ -7338,6 +7339,7 @@ export const UPSTREAM_SURFACE_MANIFEST = Object.freeze({
7338
7339
  "tests/unit/hooks/enforce-verification-gate-preserve.test.ts": true,
7339
7340
  "tests/unit/hooks/enforce-verification-gate-v1.test.ts": true,
7340
7341
  "tests/unit/hooks/enforce-verification-gate-v2.test.ts": true,
7342
+ "tests/unit/hooks/enforcement-fallback-status-aggregation.test.ts": true,
7341
7343
  "tests/unit/hooks/enforcement-fallback.test.ts": true,
7342
7344
  "tests/unit/hooks/enforcement-gates-e2e.test.ts": true,
7343
7345
  "tests/unit/hooks/host-enforcement-fallback.test.ts": true,