@codyswann/lisa 4.66.0 → 4.66.2

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 (97) hide show
  1. package/all/copy-overwrite/scripts/lisa-commit-msg-gates.mjs +1 -1
  2. package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +3 -1
  3. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  4. package/dist/core/lisa-owned-hash-ledger.js +6 -0
  5. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  6. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  7. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  8. package/dist/core/upstream-evidence-manifest.js +15 -8
  9. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  10. package/dist/opencode/plugin-templates/parity-safety-net.sh +3 -1
  11. package/package.json +4 -4
  12. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  14. package/plugins/lisa/hooks/parity-safety-net.sh +3 -1
  15. package/plugins/lisa-agy/hooks/parity-safety-net.sh +3 -1
  16. package/plugins/lisa-agy/plugin.json +1 -1
  17. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  20. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-copilot/hooks/parity-safety-net.sh +3 -1
  24. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-cursor/hooks/parity-safety-net.sh +3 -1
  26. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  28. package/plugins/lisa-expo/.codex-plugin/skills/expo-router-best-practices/SKILL.md +1 -0
  29. package/plugins/lisa-expo/.codex-plugin/skills/expo-router-best-practices/references/static-export-verification.md +54 -0
  30. package/plugins/lisa-expo/.codex-plugin/skills/expo-tailwind-setup/SKILL.md +7 -0
  31. package/plugins/lisa-expo/.codex-plugin/skills/playwright-selectors/SKILL.md +25 -0
  32. package/plugins/lisa-expo/.codex-plugin/skills/testing-library/references/mocking-patterns.md +22 -0
  33. package/plugins/lisa-expo/skills/expo-router-best-practices/SKILL.md +1 -0
  34. package/plugins/lisa-expo/skills/expo-router-best-practices/references/static-export-verification.md +54 -0
  35. package/plugins/lisa-expo/skills/expo-tailwind-setup/SKILL.md +7 -0
  36. package/plugins/lisa-expo/skills/playwright-selectors/SKILL.md +25 -0
  37. package/plugins/lisa-expo/skills/testing-library/references/mocking-patterns.md +22 -0
  38. package/plugins/lisa-expo-agy/plugin.json +1 -1
  39. package/plugins/lisa-expo-agy/skills/expo-router-best-practices/SKILL.md +1 -0
  40. package/plugins/lisa-expo-agy/skills/expo-router-best-practices/references/static-export-verification.md +54 -0
  41. package/plugins/lisa-expo-agy/skills/expo-tailwind-setup/SKILL.md +7 -0
  42. package/plugins/lisa-expo-agy/skills/playwright-selectors/SKILL.md +25 -0
  43. package/plugins/lisa-expo-agy/skills/testing-library/references/mocking-patterns.md +22 -0
  44. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-expo-copilot/skills/expo-router-best-practices/SKILL.md +1 -0
  46. package/plugins/lisa-expo-copilot/skills/expo-router-best-practices/references/static-export-verification.md +54 -0
  47. package/plugins/lisa-expo-copilot/skills/expo-tailwind-setup/SKILL.md +7 -0
  48. package/plugins/lisa-expo-copilot/skills/playwright-selectors/SKILL.md +25 -0
  49. package/plugins/lisa-expo-copilot/skills/testing-library/references/mocking-patterns.md +22 -0
  50. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-expo-cursor/skills/expo-router-best-practices/SKILL.md +1 -0
  52. package/plugins/lisa-expo-cursor/skills/expo-router-best-practices/references/static-export-verification.md +54 -0
  53. package/plugins/lisa-expo-cursor/skills/expo-tailwind-setup/SKILL.md +7 -0
  54. package/plugins/lisa-expo-cursor/skills/playwright-selectors/SKILL.md +25 -0
  55. package/plugins/lisa-expo-cursor/skills/testing-library/references/mocking-patterns.md +22 -0
  56. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  58. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  59. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  63. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  64. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  68. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  69. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  73. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  74. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  78. package/plugins/lisa-rails-agy/plugin.json +1 -1
  79. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  83. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  84. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  88. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  89. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  91. package/plugins/src/base/hooks/parity-safety-net.sh +3 -1
  92. package/plugins/src/expo/skills/expo-router-best-practices/SKILL.md +1 -0
  93. package/plugins/src/expo/skills/expo-router-best-practices/references/static-export-verification.md +54 -0
  94. package/plugins/src/expo/skills/expo-tailwind-setup/SKILL.md +7 -0
  95. package/plugins/src/expo/skills/playwright-selectors/SKILL.md +25 -0
  96. package/plugins/src/expo/skills/testing-library/references/mocking-patterns.md +22 -0
  97. package/typescript/copy-contents/.husky/commit-msg +97 -5
@@ -0,0 +1,54 @@
1
+ # Static Export Verification
2
+
3
+ When `expo export` runs with static output (`output: "static"` in app.json),
4
+ every route must produce an HTML file with the right title and the expected
5
+ initial markup. `expo export` succeeding only proves the bundle built — a
6
+ missing route, a wrong title, or an empty shell all ship green unless the
7
+ exported output itself is checked.
8
+
9
+ ## Enumerate the dynamic routes
10
+
11
+ Static export prerenders each route it can enumerate. Dynamic segments need
12
+ `generateStaticParams` — an unenumerated `[id]` route produces no page at all.
13
+ After export, enumerate the routes the app *declares* and assert each one has
14
+ a file under `dist/`:
15
+
16
+ ```typescript
17
+ import { existsSync, readdirSync } from "node:fs";
18
+ import path from "node:path";
19
+
20
+ const DIST = path.resolve("dist");
21
+
22
+ // The routes the app owns — keep this in sync with app/, or derive it from
23
+ // the route manifest expo-router emits.
24
+ const EXPECTED_ROUTES = ["index", "settings", "players/[id]"];
25
+
26
+ for (const route of EXPECTED_ROUTES) {
27
+ const html = path.join(DIST, `${route}.html`);
28
+ expect(existsSync(html)).toBe(true);
29
+ }
30
+ ```
31
+
32
+ ## Per-route titles
33
+
34
+ `<Stack.Screen options={{ title: "..." }}>` sets the native header title; the
35
+ web `<title>` comes from `Head` (`expo-router/head`). Assert the title the
36
+ exported HTML actually carries:
37
+
38
+ ```typescript
39
+ const html = readFileSync(path.join(DIST, "settings.html"), "utf8");
40
+ expect(html).toMatch(/<title>[^<]*Settings[^<]*<\/title>/);
41
+ ```
42
+
43
+ ## Expected initial content
44
+
45
+ The exported page should ship its prerendered content, not a bare shell —
46
+ that is what makes static export worth shipping at all. Assert a stable marker
47
+ of the route's expected first paint:
48
+
49
+ ```typescript
50
+ expect(html).toContain("Sign in to continue");
51
+ ```
52
+
53
+ Keep the marker to content that exists in the static HTML, never something
54
+ hydration adds later.
@@ -478,3 +478,10 @@ Add className to component props:
478
478
  ```tsx
479
479
  type Props = React.ComponentProps<typeof RNView> & { className?: string };
480
480
  ```
481
+
482
+ The same rule applies at every styling API boundary — `useCssElement`,
483
+ `cssInterop`, or `styled()`: type the wrapped component's props explicitly
484
+ (`React.ComponentProps<typeof X> & { className?: string }`) and pass props
485
+ through, rather than casting to a wider type. A cast compiles over a
486
+ prop-shape drift that an explicit type would refuse — the boundary is where
487
+ the drift is cheapest to catch.
@@ -394,6 +394,31 @@ Components from third-party libraries (e.g., `react-native-bouncy-checkbox`, `re
394
394
 
395
395
  ---
396
396
 
397
+ ## Reveal-on-Focus Assertions
398
+
399
+ `toBeVisible()` proves the element exists and is not hidden — it does NOT
400
+ prove the element crossed onto the screen. A focused element scrolled off-view
401
+ still reports visible. For any "focus reveals the element" behavior (skip
402
+ links, focus-trapped modals, scroll-into-view containers), assert on layout,
403
+ not just visibility:
404
+
405
+ ```typescript
406
+ // Rejects when the element has no box at all (display: none, detached).
407
+ const box = await page.getByTestId("dialog:panel").boundingBox();
408
+ expect(box).not.toBeNull();
409
+
410
+ // Then prove it is actually inside the viewport — the part toBeVisible()
411
+ // cannot say.
412
+ await expect(page.getByTestId("dialog:panel")).toBeInViewport();
413
+ ```
414
+
415
+ Pair them: `boundingBox()` answers "is there a box" (null means never laid
416
+ out), `toBeInViewport()` answers "did it cross onto the screen". An assertion
417
+ that skips the null check reads a missing layout as a viewport miss, which is
418
+ a different bug.
419
+
420
+ ---
421
+
397
422
  ## Implementation Checklist
398
423
 
399
424
  When adding E2E test coverage to a component:
@@ -588,3 +588,25 @@ afterAll(() => {
588
588
  console.error = originalError;
589
589
  });
590
590
  ```
591
+
592
+ ## Migrating jest.mock Usage
593
+
594
+ When moving a test file onto the managed setup, scope the migration to the
595
+ file under your hand — a suite-wide mock sweep is where subtle behavior
596
+ changes hide.
597
+
598
+ - **Prefer renderer-compatible mocks.** A mock that works in the Node
599
+ environment but reads `window`, native modules, or ESM-only entry points
600
+ fails under the jsdom/renderer the Expo preset provides. Mock the seam your
601
+ component actually imports (`jest.mock("nativewind", ...)`,
602
+ `jest.mock("@/lib/env", ...)`) — never reach around it to mock a transitive
603
+ dependency.
604
+ - **Keep factories stable and hoisted.** Jest hoists `jest.mock` calls above
605
+ imports, so a factory cannot close over outer variables. Everything the
606
+ factory needs must come from `jest.requireActual`, `jest.requireMock`, or a
607
+ `mock`-prefixed name. A factory that silently returns a different shape per
608
+ run is the migration failure that surfaces as unrelated flakes.
609
+ - **Check version compatibility, not history.** A pinned workaround for an
610
+ old jest-expo/Expo SDK issue is not a permanent blocker — verify whether the
611
+ current versions still need it before carrying it forward. Historical Expo
612
+ issues expire; copy them forward only when they reproduce.
@@ -143,20 +143,112 @@ fi
143
143
 
144
144
  echo "🤖 Checking for AI co-authorship..."
145
145
 
146
- # Accept attribution from any supported coding agent (Claude or Codex),
147
- # case-insensitively. Claude Code emits "Co-Authored-By: Claude"; the Codex CLI
148
- # emits "Co-authored-by: Codex <noreply@openai.com>".
149
- if ! printf '%s\n' "$COMMIT_MSG" | grep -Eiq "Co-authored-by:.*(Claude|Codex)"; then
146
+ # Fleet agents — the runtimes Lisa ships plugin distributions for — pass on
147
+ # the trailer alone. Any other named agent (e.g. Devin) must also carry
148
+ # AI-Agent/AI-Model/AI-Effort trailers: the gate enforces attribution, not
149
+ # agent gatekeeping, so an agent Lisa does not distribute to can still commit
150
+ # truthfully instead of forcing --no-verify. CodySwannGT/lisa#4282.
151
+ LISA_FLEET_AGENT_RE="Claude|Codex|Cursor|OpenCode|Antigravity|Copilot"
152
+ # Co-authors come from the message's trailer block via git-interpret-trailers —
153
+ # a "Co-authored-by:" string inside prose is not attribution — and every entry
154
+ # is judged on its own, so a fleet trailer can never cover a sibling trailer
155
+ # whose agent owes metadata.
156
+ COAUTHOR_TRAILERS=$(git interpret-trailers --parse "$COMMIT_MSG_FILE" 2>/dev/null | grep -iE "^Co-authored-by:" || true)
157
+
158
+ if ! printf '%s\n' "$COAUTHOR_TRAILERS" | grep -Eiq "Co-authored-by:"; then
159
+ no_coauthor=1
160
+ else
161
+ no_coauthor=0
162
+ fi
163
+
164
+ nonfleet_coauthor=0
165
+ if [ "$no_coauthor" -eq 0 ]; then
166
+ while IFS= read -r trailer; do
167
+ [ -z "$trailer" ] && continue
168
+ agent_name=$(printf '%s' "${trailer#*:}" | sed -e 's/<[^>]*>//g' -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
169
+ if ! printf '%s\n' "$agent_name" | grep -Eiq "^(${LISA_FLEET_AGENT_RE})([[:space:]]|$)"; then
170
+ nonfleet_coauthor=1
171
+ fi
172
+ done <<LISA_COAUTHOR_TRAILERS
173
+ $COAUTHOR_TRAILERS
174
+ LISA_COAUTHOR_TRAILERS
175
+ fi
176
+
177
+ if [ "$nonfleet_coauthor" -eq 1 ]; then
178
+ missing_agent_metadata=0
179
+ for trailer in AI-Agent AI-Model AI-Effort; do
180
+ if ! printf '%s\n' "$COMMIT_MSG" | grep -Eiq "^${trailer}:[[:space:]]*[^[:space:]]"; then
181
+ missing_agent_metadata=1
182
+ fi
183
+ done
184
+ if [ "$missing_agent_metadata" -eq 1 ]; then
185
+ echo ""
186
+ echo "❌ Non-fleet agents must include AI metadata trailers!"
187
+ echo ""
188
+ echo "Agents outside the supported fleet (Claude, Codex, Cursor, OpenCode,"
189
+ echo "Antigravity, Copilot) must carry provenance metadata alongside the"
190
+ echo "Co-authored-by trailer:"
191
+ echo " AI-Agent: <agent name>"
192
+ echo " AI-Model: <provider/model>"
193
+ echo " AI-Effort: <effort or runtime value>"
194
+ echo ""
195
+ lisa_commit_gate_families ai-coauthorship
196
+ exit 1
197
+ fi
198
+ elif [ "$no_coauthor" -eq 1 ]; then
150
199
  echo ""
151
200
  echo "❌ Commit message must include AI co-authorship!"
152
201
  echo ""
153
- echo "All commits must include a Co-authored-by line for a coding agent (Claude or Codex)."
202
+ echo "All commits must include a Co-authored-by line for a supported coding agent."
203
+ echo ""
204
+ echo "Expected one of these trailers:"
205
+ echo " Co-authored-by: Claude <noreply@anthropic.com>"
206
+ echo " Co-authored-by: Codex <codex@openai.com>"
207
+ echo " Co-authored-by: Cursor <noreply@cursor.com>"
208
+ echo " Co-authored-by: OpenCode <noreply@opencode.ai>"
209
+ echo " Co-authored-by: Antigravity <noreply@google.com>"
210
+ echo " Co-authored-by: Copilot <noreply@github.com>"
211
+ echo ""
212
+ echo "OpenCode commits must also include:"
213
+ echo " AI-Agent: OpenCode"
214
+ echo " AI-Model: <provider/model>"
215
+ echo " AI-Effort: <effort or runtime value>"
216
+ echo ""
217
+ echo "Agents outside the supported fleet (e.g. Devin) may commit by supplying"
218
+ echo "the same AI-Agent/AI-Model/AI-Effort trailers with their own agent name."
154
219
  echo ""
155
220
  echo "If you're using Claude Code, use the /git:commit command"
156
221
  echo "If you're using Codex, enable commit_attribution in .codex/config.toml"
222
+ echo "If you're using OpenCode, include the OpenCode trailer and AI-* metadata"
157
223
  echo ""
158
224
  lisa_commit_gate_families ai-coauthorship
159
225
  exit 1
160
226
  fi
161
227
 
228
+ if printf '%s\n' "$COAUTHOR_TRAILERS" | grep -Eiq "Co-authored-by:.*OpenCode"; then
229
+ missing_opencode_metadata=0
230
+ if ! printf '%s\n' "$COMMIT_MSG" | grep -Eiq "^AI-Agent:[[:space:]]*OpenCode[[:space:]]*$"; then
231
+ missing_opencode_metadata=1
232
+ fi
233
+ if ! printf '%s\n' "$COMMIT_MSG" | grep -Eiq "^AI-Model:[[:space:]]*[^[:space:]].*$"; then
234
+ missing_opencode_metadata=1
235
+ fi
236
+ if ! printf '%s\n' "$COMMIT_MSG" | grep -Eiq "^AI-Effort:[[:space:]]*[^[:space:]].*$"; then
237
+ missing_opencode_metadata=1
238
+ fi
239
+
240
+ if [ "$missing_opencode_metadata" -eq 1 ]; then
241
+ echo ""
242
+ echo "❌ OpenCode commits must include AI metadata trailers!"
243
+ echo ""
244
+ echo "Expected trailers:"
245
+ echo " AI-Agent: OpenCode"
246
+ echo " AI-Model: <provider/model>"
247
+ echo " AI-Effort: <effort or runtime value>"
248
+ echo ""
249
+ lisa_commit_gate_families ai-coauthorship
250
+ exit 1
251
+ fi
252
+ fi
253
+
162
254
  # END: AI GUARDRAILS