@codyswann/lisa 4.37.2 → 4.38.0

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 (127) hide show
  1. package/all/copy-contents/.gitattributes +9 -0
  2. package/all/copy-contents/gitignore +6 -0
  3. package/dist/core/learnings-merge-driver.d.ts +8 -0
  4. package/dist/core/learnings-merge-driver.d.ts.map +1 -1
  5. package/dist/core/learnings-merge-driver.js +17 -0
  6. package/dist/core/learnings-merge-driver.js.map +1 -1
  7. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  8. package/dist/core/lisa-owned-hash-ledger.js +4 -0
  9. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  10. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  11. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  12. package/dist/core/upstream-evidence-manifest.js +64 -11
  13. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  14. package/package.json +6 -4
  15. package/plugins/lisa/.claude-plugin/plugin.json +28 -1
  16. package/plugins/lisa/.codex-plugin/hooks.json +27 -0
  17. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  18. package/plugins/lisa/.codex-plugin/skills/lisa-github-write-issue/SKILL.md +11 -0
  19. package/plugins/lisa/.codex-plugin/skills/lisa-jira-write-ticket/SKILL.md +11 -0
  20. package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +11 -0
  21. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +30 -2
  22. package/plugins/lisa/hooks/inject-resolved-config.mjs +26 -7
  23. package/plugins/lisa/hooks/withdrawn-rulings.mjs +525 -0
  24. package/plugins/lisa/hooks/withdrawn-rulings.sh +24 -0
  25. package/plugins/lisa/rules/eager/config-resolution.md +3 -1
  26. package/plugins/lisa/rules/eager/withdrawn-rulings.md +69 -0
  27. package/plugins/lisa/rules/reference/config-resolution.md +1 -1
  28. package/plugins/lisa/rules/reference/withdrawn-rulings.md +114 -0
  29. package/plugins/lisa/scripts/intake-blocker-reprobe.mjs +120 -3
  30. package/plugins/lisa/skills/lisa-github-write-issue/SKILL.md +11 -0
  31. package/plugins/lisa/skills/lisa-jira-write-ticket/SKILL.md +11 -0
  32. package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +11 -0
  33. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +30 -2
  34. package/plugins/lisa-agy/plugin.json +1 -1
  35. package/plugins/lisa-agy/scripts/intake-blocker-reprobe.mjs +120 -3
  36. package/plugins/lisa-agy/skills/lisa-github-write-issue/SKILL.md +11 -0
  37. package/plugins/lisa-agy/skills/lisa-jira-write-ticket/SKILL.md +11 -0
  38. package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +11 -0
  39. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +30 -2
  40. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  43. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-copilot/.claude-plugin/plugin.json +19 -1
  46. package/plugins/lisa-copilot/hooks/inject-resolved-config.mjs +26 -7
  47. package/plugins/lisa-copilot/hooks/withdrawn-rulings.mjs +525 -0
  48. package/plugins/lisa-copilot/hooks/withdrawn-rulings.sh +24 -0
  49. package/plugins/lisa-copilot/rules/eager/config-resolution.md +3 -1
  50. package/plugins/lisa-copilot/rules/eager/withdrawn-rulings.md +69 -0
  51. package/plugins/lisa-copilot/rules/reference/config-resolution.md +1 -1
  52. package/plugins/lisa-copilot/rules/reference/withdrawn-rulings.md +114 -0
  53. package/plugins/lisa-copilot/scripts/intake-blocker-reprobe.mjs +120 -3
  54. package/plugins/lisa-copilot/skills/lisa-github-write-issue/SKILL.md +11 -0
  55. package/plugins/lisa-copilot/skills/lisa-jira-write-ticket/SKILL.md +11 -0
  56. package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +11 -0
  57. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +30 -2
  58. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-cursor/hooks/hooks.json +10 -0
  60. package/plugins/lisa-cursor/hooks/inject-resolved-config.mjs +26 -7
  61. package/plugins/lisa-cursor/hooks/withdrawn-rulings.mjs +525 -0
  62. package/plugins/lisa-cursor/hooks/withdrawn-rulings.sh +24 -0
  63. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +1 -1
  64. package/plugins/lisa-cursor/rules/config-resolution.mdc +3 -1
  65. package/plugins/lisa-cursor/rules/withdrawn-rulings-reference.mdc +119 -0
  66. package/plugins/lisa-cursor/rules/withdrawn-rulings.mdc +74 -0
  67. package/plugins/lisa-cursor/scripts/intake-blocker-reprobe.mjs +120 -3
  68. package/plugins/lisa-cursor/skills/lisa-github-write-issue/SKILL.md +11 -0
  69. package/plugins/lisa-cursor/skills/lisa-jira-write-ticket/SKILL.md +11 -0
  70. package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +11 -0
  71. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +30 -2
  72. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  74. package/plugins/lisa-expo-agy/plugin.json +1 -1
  75. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  79. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  80. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  84. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  85. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  89. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  90. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  91. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  92. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  93. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  94. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  95. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  96. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  97. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  98. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  99. package/plugins/lisa-rails-agy/plugin.json +1 -1
  100. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  101. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  102. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  103. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  104. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  105. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  106. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  107. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  108. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  109. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  110. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  111. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  112. package/plugins/src/base/.claude-plugin/plugin.json +27 -0
  113. package/plugins/src/base/hooks/inject-resolved-config.mjs +26 -7
  114. package/plugins/src/base/hooks/withdrawn-rulings.mjs +525 -0
  115. package/plugins/src/base/hooks/withdrawn-rulings.sh +24 -0
  116. package/plugins/src/base/rules/eager/config-resolution.md +3 -1
  117. package/plugins/src/base/rules/eager/withdrawn-rulings.md +69 -0
  118. package/plugins/src/base/rules/reference/config-resolution.md +1 -1
  119. package/plugins/src/base/rules/reference/withdrawn-rulings.md +114 -0
  120. package/plugins/src/base/scripts/intake-blocker-reprobe.mjs +120 -3
  121. package/plugins/src/base/skills/lisa-github-write-issue/SKILL.md +11 -0
  122. package/plugins/src/base/skills/lisa-jira-write-ticket/SKILL.md +11 -0
  123. package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +11 -0
  124. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +30 -2
  125. package/scripts/lib/hook-registration-audit.mjs +612 -0
  126. package/scripts/measure-tmpdir-growth.mjs +925 -0
  127. package/typescript/copy-contents/.husky/pre-push +98 -26
@@ -584,41 +584,113 @@ else
584
584
  echo " Check that TMPDIR (${TMPDIR:-/tmp}) exists and is writable." >&2
585
585
  exit 1
586
586
  fi
587
- # bun's own diagnostics are kept rather than discarded. "Lockfile not found"
588
- # is the difference between a broken audit and a clean one, and throwing it
589
- # away is how a failed command comes to read as a measured zero.
590
- bun audit --production --json > "$AUDIT_OUTPUT" 2>"$AUDIT_STDERR" || true
591
- if [ ! -s "$AUDIT_OUTPUT" ]; then
587
+ # The audit is a NETWORK call, and the network is the one input to this gate
588
+ # that answers differently to the same question. Measured 2026-09-04, three
589
+ # consecutive `bun audit --production --json` invocations in one directory
590
+ # seconds apart: run 1 returned 0 bytes with `Timeout: audit request failed`,
591
+ # runs 2 and 3 returned 6036 bytes of valid JSON. Read as a single attempt
592
+ # that is a blocked `git push` — and the push has already paid for the whole
593
+ # gate chain (tests, typecheck, dead-code, traceability, mutation) because
594
+ # the audit sits near the end of it. One flaky call, one full cycle.
595
+ #
596
+ # So the call is retried, and ONLY the indeterminate outcome is retried:
597
+ #
598
+ # determinate — the payload parsed. Break immediately, whether it is
599
+ # clean or names a critical advisory. A real vulnerability
600
+ # fails on the FIRST call and is never retried into a pass;
601
+ # a clean audit pays nothing for a knob it did not need.
602
+ # indeterminate — nothing parsed: zero bytes, or bytes that are neither
603
+ # JSON nor gzipped JSON. The audit did not happen. That is
604
+ # what a retry can change, and the only thing it may.
605
+ #
606
+ # The direction matters more than the retry does. Retrying a determinate
607
+ # answer is how a gate talks itself out of a finding; this loop cannot,
608
+ # because a parsed payload leaves the loop before any backoff is reached.
609
+ #
610
+ # Three outcomes, three sentences. "The audit did not run" is never collapsed
611
+ # into "the audit found nothing" (that is the fail-open this block exists to
612
+ # remove) nor into "the audit found something" (that sends the reader hunting
613
+ # a vulnerability that was never measured). When every attempt is
614
+ # indeterminate the block still refuses, with the same two distinguishable
615
+ # messages it printed before — a retry that muted either would trade a noisy
616
+ # flake for a silent hole.
617
+ AUDIT_ATTEMPTS="${LISA_AUDIT_ATTEMPTS:-3}"
618
+ AUDIT_RETRY_DELAY="${LISA_AUDIT_RETRY_DELAY:-2}"
619
+ # A non-numeric knob is a typo, not an instruction. This hook does not run
620
+ # under `set -e`, so `[ abc -le 3 ]` would print an error and the loop would
621
+ # behave in a way nobody chose; falling back to the default keeps a
622
+ # fat-fingered env var from quietly disarming the retry.
623
+ case "$AUDIT_ATTEMPTS" in ''|*[!0-9]*) AUDIT_ATTEMPTS=3 ;; esac
624
+ case "$AUDIT_RETRY_DELAY" in ''|*[!0-9]*) AUDIT_RETRY_DELAY=2 ;; esac
625
+ [ "$AUDIT_ATTEMPTS" -ge 1 ] || AUDIT_ATTEMPTS=1
626
+
627
+ AUDIT_JSON=""
628
+ # "" once a payload parsed; otherwise which refusal the last attempt earned.
629
+ AUDIT_INDETERMINATE=""
630
+ AUDIT_ATTEMPT=1
631
+ while [ "$AUDIT_ATTEMPT" -le "$AUDIT_ATTEMPTS" ]; do
632
+ # bun's own diagnostics are kept rather than discarded. "Lockfile not
633
+ # found" is the difference between a broken audit and a clean one, and
634
+ # throwing it away is how a failed command comes to read as a measured
635
+ # zero. "Timeout: audit request failed" is the line that names this bug,
636
+ # and an agent grepping the push output for its own expected failure
637
+ # shapes has already thrown it away once.
638
+ bun audit --production --json > "$AUDIT_OUTPUT" 2>"$AUDIT_STDERR" || true
639
+ if [ ! -s "$AUDIT_OUTPUT" ]; then
640
+ AUDIT_INDETERMINATE="empty"
641
+ elif jq empty "$AUDIT_OUTPUT" >/dev/null 2>&1; then
642
+ AUDIT_JSON=$(cat "$AUDIT_OUTPUT")
643
+ AUDIT_INDETERMINATE=""
644
+ break
645
+ else
646
+ # Bun can return gzip-compressed JSON on stdout while still reporting a
647
+ # parse error on stderr. Normalize that transport shape before applying
648
+ # Lisa's advisory allowlist.
649
+ DECOMPRESSED_AUDIT_OUTPUT="$(mktemp "${TMPDIR:-/tmp}/bun-audit-gz.XXXXXXXX")"
650
+ if [ -n "$DECOMPRESSED_AUDIT_OUTPUT" ]; then
651
+ gzip -dc "$AUDIT_OUTPUT" > "$DECOMPRESSED_AUDIT_OUTPUT" 2>/dev/null || true
652
+ fi
653
+ # `-s` before `jq empty`: an EMPTY file passes `jq empty` (no input is
654
+ # not invalid input), so a gunzip that failed and wrote nothing would be
655
+ # accepted as valid JSON and set AUDIT_JSON to the empty string.
656
+ if [ -s "$DECOMPRESSED_AUDIT_OUTPUT" ] && jq empty "$DECOMPRESSED_AUDIT_OUTPUT" >/dev/null 2>&1; then
657
+ AUDIT_JSON=$(cat "$DECOMPRESSED_AUDIT_OUTPUT")
658
+ rm -f "$DECOMPRESSED_AUDIT_OUTPUT"
659
+ AUDIT_INDETERMINATE=""
660
+ break
661
+ fi
662
+ rm -f "$DECOMPRESSED_AUDIT_OUTPUT"
663
+ AUDIT_INDETERMINATE="unparseable"
664
+ fi
665
+ if [ "$AUDIT_ATTEMPT" -lt "$AUDIT_ATTEMPTS" ]; then
666
+ echo "⏳ Security audit attempt $AUDIT_ATTEMPT of $AUDIT_ATTEMPTS parsed no advisory data (the audit did not run — this is not a finding); retrying in ${AUDIT_RETRY_DELAY}s..." >&2
667
+ if [ "$AUDIT_RETRY_DELAY" -gt 0 ]; then
668
+ sleep "$AUDIT_RETRY_DELAY"
669
+ fi
670
+ AUDIT_RETRY_DELAY=$((AUDIT_RETRY_DELAY * 2))
671
+ fi
672
+ AUDIT_ATTEMPT=$((AUDIT_ATTEMPT + 1))
673
+ done
674
+
675
+ if [ "$AUDIT_INDETERMINATE" = "empty" ]; then
592
676
  echo "❌ Push blocked: bun audit produced no output, so nothing was audited." >&2
593
677
  echo " This is NOT a clean result — a clean audit prints JSON ({} when" >&2
594
678
  echo " there are no advisories). Empty output means the audit did not run." >&2
679
+ echo " Tried $AUDIT_ATTEMPTS attempt(s) with backoff; every one came back" >&2
680
+ echo " empty, so this is not the transient registry timeout a retry clears." >&2
595
681
  if [ -s "$AUDIT_STDERR" ]; then
596
682
  echo " bun said:" >&2
597
683
  sed 's/^/ /' "$AUDIT_STDERR" >&2
598
684
  fi
599
685
  rm -f "$AUDIT_OUTPUT" "$AUDIT_STDERR"
600
686
  exit 1
601
- elif jq empty "$AUDIT_OUTPUT" >/dev/null 2>&1; then
602
- AUDIT_JSON=$(cat "$AUDIT_OUTPUT")
603
- else
604
- DECOMPRESSED_AUDIT_OUTPUT="$(mktemp "${TMPDIR:-/tmp}/bun-audit-gz.XXXXXXXX")"
605
- if [ -n "$DECOMPRESSED_AUDIT_OUTPUT" ]; then
606
- gzip -dc "$AUDIT_OUTPUT" > "$DECOMPRESSED_AUDIT_OUTPUT" 2>/dev/null || true
607
- fi
608
- # `-s` before `jq empty`: an EMPTY file passes `jq empty` (no input is
609
- # not invalid input), so a gunzip that failed and wrote nothing would be
610
- # accepted as valid JSON and set AUDIT_JSON to the empty string.
611
- if [ -s "$DECOMPRESSED_AUDIT_OUTPUT" ] && jq empty "$DECOMPRESSED_AUDIT_OUTPUT" >/dev/null 2>&1; then
612
- AUDIT_JSON=$(cat "$DECOMPRESSED_AUDIT_OUTPUT")
613
- rm -f "$DECOMPRESSED_AUDIT_OUTPUT"
614
- else
615
- rm -f "$DECOMPRESSED_AUDIT_OUTPUT" "$AUDIT_OUTPUT" "$AUDIT_STDERR"
616
- echo "❌ Push blocked: bun audit output is neither JSON nor gzipped JSON," >&2
617
- echo " so no advisory data was parsed and nothing was audited." >&2
618
- echo " This is NOT a clean result. Re-run 'bun audit --production --json'" >&2
619
- echo " to see what it emitted." >&2
620
- exit 1
621
- fi
687
+ elif [ "$AUDIT_INDETERMINATE" = "unparseable" ]; then
688
+ rm -f "$AUDIT_OUTPUT" "$AUDIT_STDERR"
689
+ echo "❌ Push blocked: bun audit output is neither JSON nor gzipped JSON," >&2
690
+ echo " so no advisory data was parsed and nothing was audited." >&2
691
+ echo " This is NOT a clean result. Re-run 'bun audit --production --json'" >&2
692
+ echo " to see what it emitted. Tried $AUDIT_ATTEMPTS attempt(s)." >&2
693
+ exit 1
622
694
  fi
623
695
  rm -f "$AUDIT_OUTPUT" "$AUDIT_STDERR"
624
696
  UNFIXED_HIGH=$(echo "$AUDIT_JSON" | jq -r --arg ids "$AUDIT_EXCLUSIONS" '