@codyswann/lisa 4.33.3 → 4.33.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.
Files changed (87) hide show
  1. package/dist/configs/eslint/expo.d.ts.map +1 -1
  2. package/dist/configs/eslint/expo.js +4 -7
  3. package/dist/configs/eslint/expo.js.map +1 -1
  4. package/dist/configs/eslint/view-gate.d.ts +42 -0
  5. package/dist/configs/eslint/view-gate.d.ts.map +1 -0
  6. package/dist/configs/eslint/view-gate.js +110 -0
  7. package/dist/configs/eslint/view-gate.js.map +1 -0
  8. package/dist/configs/repo-scan.d.ts +25 -0
  9. package/dist/configs/repo-scan.d.ts.map +1 -0
  10. package/dist/configs/repo-scan.js +83 -0
  11. package/dist/configs/repo-scan.js.map +1 -0
  12. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  13. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  14. package/dist/core/upstream-evidence-manifest.js +20 -7
  15. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  16. package/eslint-plugin-component-structure/README.md +85 -2
  17. package/eslint-plugin-component-structure/__tests__/no-hooks-in-view.test.js +229 -0
  18. package/eslint-plugin-component-structure/__tests__/no-return-in-view.test.js +185 -0
  19. package/eslint-plugin-component-structure/__tests__/plugin-index.test.js +8 -1
  20. package/eslint-plugin-component-structure/index.js +4 -1
  21. package/eslint-plugin-component-structure/lib/view-file-scope.js +62 -0
  22. package/eslint-plugin-component-structure/rules/no-hooks-in-view.js +101 -0
  23. package/eslint-plugin-component-structure/rules/no-return-in-view.js +133 -62
  24. package/expo/copy-overwrite/eslint.expo.ts +88 -1
  25. package/package.json +4 -4
  26. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  28. package/plugins/lisa-agy/plugin.json +1 -1
  29. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  31. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  32. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  38. package/plugins/lisa-expo/.codex-plugin/skills/container-view-pattern/SKILL.md +80 -24
  39. package/plugins/lisa-expo/.codex-plugin/skills/container-view-pattern/scripts/validate_component.py +166 -43
  40. package/plugins/lisa-expo/skills/container-view-pattern/SKILL.md +80 -24
  41. package/plugins/lisa-expo/skills/container-view-pattern/scripts/validate_component.py +166 -43
  42. package/plugins/lisa-expo-agy/plugin.json +1 -1
  43. package/plugins/lisa-expo-agy/skills/container-view-pattern/SKILL.md +80 -24
  44. package/plugins/lisa-expo-agy/skills/container-view-pattern/scripts/validate_component.py +166 -43
  45. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-expo-copilot/skills/container-view-pattern/SKILL.md +80 -24
  47. package/plugins/lisa-expo-copilot/skills/container-view-pattern/scripts/validate_component.py +166 -43
  48. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-expo-cursor/skills/container-view-pattern/SKILL.md +80 -24
  50. package/plugins/lisa-expo-cursor/skills/container-view-pattern/scripts/validate_component.py +166 -43
  51. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  53. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  54. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  58. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  59. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  63. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  64. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  68. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  69. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  73. package/plugins/lisa-rails-agy/plugin.json +1 -1
  74. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  78. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  79. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  83. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  84. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  86. package/plugins/src/expo/skills/container-view-pattern/SKILL.md +80 -24
  87. package/plugins/src/expo/skills/container-view-pattern/scripts/validate_component.py +166 -43
@@ -10,11 +10,29 @@ This script validates that a component directory follows the Container/View patt
10
10
  - Has index.tsx with correct export
11
11
  - View uses memo() wrapper
12
12
  - View has displayName
13
- - View uses arrow function shorthand
13
+ - View is an arrow function with an expression body (declaration form is a
14
+ violation, not an alternative spelling)
15
+ - View calls no hooks — matched by SHAPE (`use` + uppercase), never by a list of
16
+ names, because the call that motivated this check was a project-local custom
17
+ hook that no list would have contained
18
+
19
+ One check reports as an ADVISORY rather than an error: "Container renders JSX
20
+ besides the View". It is a whole-file text scan that cannot tell a returned JSX
21
+ tree from JSX inside a callback, so a Container holding a legitimate `renderItem`
22
+ trips it — and moving a `renderItem` out of a View is one of the sanctioned fixes
23
+ for the View hook ban. It prints and does not fail.
24
+
25
+ This is a fast pre-check, not the gate. ESLint reads the AST of every file;
26
+ this reads one directory with regexes. When they disagree, ESLint is right.
14
27
 
15
28
  Usage:
16
29
  python3 validate_component.py <path-to-component-directory>
17
30
 
31
+ The script ships inside the Lisa plugin, not in a consumer's `.claude/skills/`,
32
+ so invoke it through the plugin root:
33
+
34
+ python3 "${CLAUDE_PLUGIN_ROOT:-node_modules/@codyswann/lisa/plugins/lisa-expo}/skills/container-view-pattern/scripts/validate_component.py" <path>
35
+
18
36
  Example:
19
37
  python3 validate_component.py features/player-kanban/components/AddColumnButton
20
38
  """
@@ -25,21 +43,118 @@ import sys
25
43
  from pathlib import Path
26
44
 
27
45
 
28
- def validate_component(component_path: str) -> tuple[bool, list[str]]:
46
+ HOOK_CALL = re.compile(r"\b(use[A-Z]\w*)\s*\(")
47
+ """Every hook call, by SHAPE.
48
+
49
+ `use` followed by an uppercase letter is React's own definition of a hook name,
50
+ so this matches `useState`, `useMemo`, and every project-local custom hook
51
+ alike. It is a shape and never a list: a list is what let
52
+ `useCreateNoteQuickActionEnabled()` through.
53
+
54
+ It also matches hook calls inside comments and strings. That is the accepted
55
+ cost of a regex pre-check; ESLint's `component-structure/no-hooks-in-view` reads
56
+ the AST and is the gate.
57
+ """
58
+
59
+
60
+ def _arrow_body_is_block(source: str, start: int) -> bool:
61
+ """
62
+ Whether the arrow beginning at `start` has a block body.
63
+
64
+ Walks to the first top-level `=>` instead of matching a parameter list with
65
+ `\\([^)]*\\)`, which fails on any nested paren — a destructured parameter with
66
+ a default, a type annotation carrying a function type, or a parenthesised
67
+ union.
68
+
69
+ Args:
70
+ source: The View file's text.
71
+ start: Index just past the `const <Name>View` binding.
72
+
73
+ Returns:
74
+ True when the arrow's body opens with `{`.
75
+ """
76
+ depth = 0
77
+ index = start
78
+ while index < len(source) - 1:
79
+ char = source[index]
80
+ if char in "([{":
81
+ depth += 1
82
+ elif char in ")]}":
83
+ depth -= 1
84
+ elif char == ";" and depth == 0:
85
+ return False
86
+ elif depth == 0 and source[index : index + 2] == "=>":
87
+ rest = source[index + 2 :].lstrip()
88
+ return rest.startswith("{")
89
+ index += 1
90
+ return False
91
+
92
+
93
+ def view_form_errors(component_name: str, view_content: str) -> list[str]:
94
+ """
95
+ Errors about the FORM of the View component.
96
+
97
+ The requirement is an arrow function with an expression body. A function
98
+ declaration cannot have one, so declaration form is banned by construction
99
+ rather than by scanning for the word "function" — which would fire on JSDoc
100
+ prose, on local render helpers, and on disable-comment justifications, none
101
+ of which are the View component.
102
+
103
+ Args:
104
+ component_name: The component directory's name, without the View suffix.
105
+ view_content: The View file's text.
106
+
107
+ Returns:
108
+ Zero or one error message.
109
+ """
110
+ name = f"{component_name}View"
111
+ expected = f"const {name} = (props) => (...)"
112
+
113
+ if re.search(rf"\bfunction\s+{re.escape(name)}\b", view_content):
114
+ return [
115
+ f"View must be an arrow function with an expression body: {expected}. "
116
+ "A function declaration cannot have one, so it always carries a statement list."
117
+ ]
118
+
119
+ function_expression = re.search(
120
+ rf"\bconst\s+{re.escape(name)}\b[^=]*=\s*function\b", view_content
121
+ )
122
+ if function_expression:
123
+ return [
124
+ f"View must be an arrow function with an expression body: {expected}. "
125
+ "A function expression cannot have one."
126
+ ]
127
+
128
+ binding = re.search(rf"\bconst\s+{re.escape(name)}\b", view_content)
129
+ if binding and _arrow_body_is_block(view_content, binding.end()):
130
+ return [
131
+ "View should use arrow function shorthand: () => (...) instead of () => { return (...) }"
132
+ ]
133
+
134
+ return []
135
+
136
+
137
+ def validate_component(component_path: str) -> tuple[bool, list[str], list[str]]:
29
138
  """
30
139
  Validate a component directory follows Container/View pattern.
31
140
 
141
+ Errors and advisories are separated because one check here cannot decide
142
+ what it reports on — see the Container JSX scan below. A check that cannot
143
+ tell a violation from a legitimate shape must say so rather than fail the
144
+ run; a confident wrong verdict is worse than a flagged uncertainty.
145
+
32
146
  Args:
33
147
  component_path: Path to the component directory
34
148
 
35
149
  Returns:
36
- Tuple of (is_valid, list of error messages)
150
+ Tuple of (is_valid, list of error messages, list of advisory messages)
37
151
  """
38
152
  errors = []
153
+ advisories = []
39
154
  component_dir = Path(component_path)
40
155
 
41
156
  if not component_dir.is_dir():
42
- return False, [f"Path is not a directory: {component_path}"]
157
+ return False, [f"Path is not a directory: {component_path}"], advisories
43
158
 
44
159
  component_name = component_dir.name
45
160
 
@@ -92,39 +207,24 @@ def validate_component(component_path: str) -> tuple[bool, list[str]]:
92
207
  if not re.search(display_name_pattern, view_content):
93
208
  errors.append(f"View should have displayName: {component_name}View.displayName = \"{component_name}View\"")
94
209
 
95
- # Check for block body (return statement) in main component
96
- # This is a simplified check - ESLint does the full validation
97
- block_body_pattern = rf"const\s+{component_name}View\s*=\s*\([^)]*\)\s*=>\s*{{"
98
- if re.search(block_body_pattern, view_content):
99
- errors.append("View should use arrow function shorthand: () => (...) instead of () => { return (...) }")
100
-
101
- # Check for hooks in View (they should be in Container)
102
- hook_patterns = [
103
- r"\buse[A-Z]\w+\s*\(", # General hook pattern
104
- r"\buseState\s*\(",
105
- r"\buseEffect\s*\(",
106
- r"\buseMemo\s*\(",
107
- r"\buseCallback\s*\(",
108
- r"\buseReducer\s*\(",
109
- r"\buseContext\s*\(",
110
- ]
111
-
112
- for hook_pattern in hook_patterns:
113
- # Exclude memo import check
114
- if hook_pattern == r"\buse[A-Z]\w+\s*\(":
115
- # More specific check to avoid false positives
116
- if re.search(r"\buseState\s*\(", view_content):
117
- errors.append("View should not contain useState - move to Container")
118
- break
119
- if re.search(r"\buseEffect\s*\(", view_content):
120
- errors.append("View should not contain useEffect - move to Container")
121
- break
122
- if re.search(r"\buseMemo\s*\(", view_content):
123
- errors.append("View should not contain useMemo - move to Container")
124
- break
125
- if re.search(r"\buseCallback\s*\(", view_content):
126
- errors.append("View should not contain useCallback - move to Container")
127
- break
210
+ # Check the View component's form.
211
+ #
212
+ # The old check was `const {name}View = ([^)]*) => {` — arrow-only, and
213
+ # therefore blind to `function {name}View(...) {`, independently
214
+ # reproducing the exact defect the ESLint rule carried. It also broke on
215
+ # any parameter list containing a nested paren.
216
+ errors.extend(view_form_errors(component_name, view_content))
217
+
218
+ # Check for hooks in View (they should be in Container).
219
+ #
220
+ # One generic shape match, deliberately. The previous version listed
221
+ # `\buse[A-Z]\w+\s*\(` first and then narrowed to four hardcoded names
222
+ # and `break`ed, so the general pattern was UNREACHABLE — dead code that
223
+ # read as coverage. A project-local hook such as
224
+ # `useCreateNoteQuickActionEnabled()` matched the pattern that was never
225
+ # evaluated and none of the four that were.
226
+ for hook in sorted(set(HOOK_CALL.findall(view_content))):
227
+ errors.append(f"View should not contain {hook} - move to Container")
128
228
 
129
229
  # Validate Container file
130
230
  if container_file.exists():
@@ -140,14 +240,31 @@ def validate_component(component_path: str) -> tuple[bool, list[str]]:
140
240
  if not re.search(return_view_pattern, container_content):
141
241
  errors.append(f"Container should return <{component_name}View />")
142
242
 
143
- # Check that Container ONLY renders View (no other JSX elements)
144
- # Find all JSX tags in Container (excluding the View)
243
+ # ADVISORY, not an error — and deliberately so.
244
+ #
245
+ # "Container should ONLY render View" is a naive `<([A-Z]\w*)` scan over
246
+ # the ENTIRE container file. It cannot tell a component's returned JSX
247
+ # tree from JSX inside a callback, so a Container holding a perfectly
248
+ # legitimate `renderItem` — `useCallback(({item}) => <Row … />, […])` —
249
+ # trips it.
250
+ #
251
+ # That matters now that Views may not call hooks: moving a renderItem
252
+ # callback to the Container is one of the two sanctioned fixes, and
253
+ # Containers ARE allowed to hold logic, including a callback that
254
+ # returns JSX. Left as an error, this check would reject the very
255
+ # migration the View rules ask for.
256
+ #
257
+ # So it reports and does not fail. Scoping it to the returned tree needs
258
+ # a parser, which a regex pre-check is not; until then, saying plainly
259
+ # what it cannot distinguish beats a confident wrong verdict.
145
260
  all_jsx_pattern = r"<([A-Z][a-zA-Z0-9]*)"
146
261
  jsx_matches = re.findall(all_jsx_pattern, container_content)
147
262
  other_components = [m for m in jsx_matches if m != f"{component_name}View"]
148
263
  if other_components:
149
- errors.append(
150
- f"Container should ONLY render {component_name}View, but found: {', '.join(set(other_components))}"
264
+ advisories.append(
265
+ f"Container renders JSX besides {component_name}View: {', '.join(sorted(set(other_components)))}. "
266
+ "This is a whole-file text scan and cannot tell a returned JSX tree from JSX inside a callback, "
267
+ "so a legitimate renderItem callback lands here too. Review it; this does not fail validation."
151
268
  )
152
269
 
153
270
  # Check for extra files
@@ -178,7 +295,7 @@ def validate_component(component_path: str) -> tuple[bool, list[str]]:
178
295
  if not is_allowed and item.is_file():
179
296
  errors.append(f"Unexpected file in component directory: {item.name}")
180
297
 
181
- return len(errors) == 0, errors
298
+ return len(errors) == 0, errors, advisories
182
299
 
183
300
 
184
301
  def main():
@@ -193,7 +310,13 @@ def main():
193
310
  print(f"Validating component: {component_path}")
194
311
  print("-" * 50)
195
312
 
196
- is_valid, errors = validate_component(component_path)
313
+ is_valid, errors, advisories = validate_component(component_path)
314
+
315
+ if advisories:
316
+ print("Advisories (reviewed by a human, not a failure):")
317
+ for advisory in advisories:
318
+ print(f" ~ {advisory}")
319
+ print("-" * 50)
197
320
 
198
321
  if is_valid:
199
322
  print("Component follows Container/View pattern")
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.33.3",
3
+ "version": "4.33.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": "4.33.3",
3
+ "version": "4.33.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": "4.33.3",
3
+ "version": "4.33.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": "4.33.3",
3
+ "version": "4.33.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": "4.33.3",
3
+ "version": "4.33.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-phaser",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.33.3",
3
+ "version": "4.33.5",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"