@codyswann/lisa 4.8.2 → 4.8.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 (83) hide show
  1. package/all/copy-overwrite/scripts/lisa-gates.mjs +212 -3
  2. package/all/copy-overwrite/scripts/lisa-reconcile-policy.mjs +11 -0
  3. package/all/copy-overwrite/scripts/lisa-run-gates.mjs +232 -67
  4. package/dist/cli/gate-report-cells.d.ts +1 -1
  5. package/dist/cli/gate-report-cells.d.ts.map +1 -1
  6. package/dist/cli/gate-report-cells.js +18 -2
  7. package/dist/cli/gate-report-cells.js.map +1 -1
  8. package/dist/cli/gate-report-joins.d.ts.map +1 -1
  9. package/dist/cli/gate-report-joins.js +36 -4
  10. package/dist/cli/gate-report-joins.js.map +1 -1
  11. package/dist/cli/gate-report-registry.d.ts +30 -0
  12. package/dist/cli/gate-report-registry.d.ts.map +1 -1
  13. package/dist/cli/gate-report-registry.js +25 -0
  14. package/dist/cli/gate-report-registry.js.map +1 -1
  15. package/dist/core/gate-declaration-drift.d.ts +18 -0
  16. package/dist/core/gate-declaration-drift.d.ts.map +1 -1
  17. package/dist/core/gate-declaration-drift.js +30 -1
  18. package/dist/core/gate-declaration-drift.js.map +1 -1
  19. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  20. package/dist/core/lisa-owned-hash-ledger.js +6 -0
  21. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  22. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  23. package/dist/core/upstream-evidence-manifest.js +9 -6
  24. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  25. package/package.json +1 -1
  26. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  28. package/plugins/lisa/.codex-plugin/skills/lisa-doctor/SKILL.md +41 -0
  29. package/plugins/lisa/skills/lisa-doctor/SKILL.md +41 -0
  30. package/plugins/lisa-agy/plugin.json +1 -1
  31. package/plugins/lisa-agy/skills/lisa-doctor/SKILL.md +41 -0
  32. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  34. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  35. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-copilot/skills/lisa-doctor/SKILL.md +41 -0
  39. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-cursor/skills/lisa-doctor/SKILL.md +41 -0
  41. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  43. package/plugins/lisa-expo-agy/plugin.json +1 -1
  44. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  48. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  49. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  53. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  54. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  58. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  59. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  63. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  64. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  68. package/plugins/lisa-rails-agy/plugin.json +1 -1
  69. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  73. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  74. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  78. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  79. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  81. package/plugins/src/base/skills/lisa-doctor/SKILL.md +41 -0
  82. package/scripts/lisa-github-rulesets.sh +15 -5
  83. package/scripts/lisa-ruleset-payload.mjs +30 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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.8.2",
3
+ "version": "4.8.4",
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"
@@ -569,6 +569,37 @@ additive-only `addRequiredChecks`, which is still read but can never express "st
569
569
  Both surfaces name the ruleset a repair writes to, so `--ruleset` is needed only for a
570
570
  gate-DERIVED context on a repository whose rulesets are ambiguous.
571
571
 
572
+ **2b. A gate proved OUTSIDE the quality facade names its own check-run chain.** A run-mode gate's
573
+ required context is derived by prefixing the gate's label with the chain of jobs that reach the
574
+ facade. When a project proves one property from a workflow of its own instead, that chain describes
575
+ a route that never reaches the prover, and the derived name is one nothing posts — which does not
576
+ turn a pull request red, it holds it at "Expected — Waiting for status to be reported" for ever.
577
+ Declare the real chain on that moment:
578
+
579
+ ```json
580
+ "gates": {
581
+ "e2e-browser": {
582
+ "run": "test:e2e:pr",
583
+ "pull-request": {
584
+ "level": "required",
585
+ "caller_chain": ["🎭 PR Browser Coverage"]
586
+ }
587
+ }
588
+ }
589
+ ```
590
+
591
+ Read the chain off a completed run, never off the YAML: a check run's reported name is the
592
+ `/`-joined chain of the JOB names that reach it, outermost first, and the top workflow's own `name:`
593
+ never appears in it. Take it from
594
+ `gh api repos/OWNER/NAME/commits/SHA/check-runs --paginate --slurp`, or let
595
+ `lisa-gates.mjs verify-contexts --posted=<file>` compare a derivation against what actually posted.
596
+ Either spelling works — `["A", "B"]` or `"A / B"` — and the override replaces the caller's chain for
597
+ that gate only; every other gate keeps deriving exactly what it derived before. It is declared per
598
+ MOMENT, because the same job posts a one-level name on the pull-request path and a two-level one on
599
+ the release path. Declaring it on the whole gate, on an `await`ing moment, at a moment that posts no
600
+ status, or with a blank level is refused by `lisa-gates.mjs validate` — at declaration time, which
601
+ is the last point at which any of those can still fail loudly.
602
+
572
603
  **3. Keep both names during a rename.** `--previous=<old label>` requires the old and the new
573
604
  context simultaneously for one release. Without it the reconciliation reports the still-live old
574
605
  context as EXTRA (and `--prune` would delete it) while in-flight pull requests wait on a context
@@ -588,6 +619,16 @@ That rule construction is itself config-driven now. `all/github-rulesets/base.js
588
619
  `policy.review.required_approving_review_count`, none of which config could express while the
589
620
  template owned them.
590
621
 
622
+ `policy.review.require_extra_approval_for_unattributed_changes` is declarable for a reason worth
623
+ stating, because its default is not "leave it alone". Measured against the live rulesets API on
624
+ 2026-08-25: a `pull_request` rule sent WITHOUT the parameter came back with it `true`; set
625
+ explicitly to `false` it came back `false`; sent again without it, it came back `true`. GitHub
626
+ re-applies its own default on every write that omits the field. So an operator who wants it OFF
627
+ cannot hold it off unless the payload names it, and an operator who wants it ON is recording no
628
+ choice at all — the value is whatever GitHub's default happens to be. Declaring it pins the choice
629
+ and makes it visible to the reconciler; declaring nothing keeps the payload byte-for-byte what it
630
+ was, parameter absent.
631
+
591
632
  ## Secrets configuration
592
633
 
593
634
  Run the secrets health checks through the skill that owns the contract, rather than reimplementing
@@ -570,11 +570,21 @@ ruleset_added_contexts() {
570
570
  # True when everything the payload asks for is ALREADY true of the live ruleset.
571
571
  #
572
572
  # Deliberately a subset test rather than an equality test: GitHub echoes back
573
- # parameters it filled in with its own defaults (`required_reviewers`,
574
- # `require_extra_approval_for_unattributed_changes`, ...) which no template
575
- # names. Comparing whole documents would report drift on every run and make
576
- # "nothing to do" unreachable — the AC's second scenario would then never hold
577
- # even on a repository that needs no change.
573
+ # parameters it filled in with its own defaults (`required_reviewers`, ...)
574
+ # which no template names. Comparing whole documents would report drift on
575
+ # every run and make "nothing to do" unreachable — the AC's second scenario
576
+ # would then never hold even on a repository that needs no change.
577
+ #
578
+ # `require_extra_approval_for_unattributed_changes` used to be listed here as
579
+ # another such default, and that reading was measured wrong on 2026-08-25. It
580
+ # IS filled in when omitted, but the fill is `true` and it is re-applied on
581
+ # every write: a rule PUT without the field came back `true` even after being
582
+ # explicitly set to `false`. Being invisible to a subset test is therefore not
583
+ # harmless for it — an operator who wants it off cannot keep it off, and the
584
+ # reconciliation reports no drift while GitHub turns it back on. It is now
585
+ # declarable as `policy.review.require_extra_approval_for_unattributed_changes`
586
+ # (CodySwannGT/lisa#3096), and once declared the payload names it, so this
587
+ # subset test compares it like any other parameter.
578
588
  ruleset_is_current() {
579
589
  local live="$1"
580
590
  local payload="$2"
@@ -107,6 +107,31 @@ export const REVIEW_DEFAULTS = Object.freeze({
107
107
  require_code_owner_review: false,
108
108
  });
109
109
 
110
+ /**
111
+ * The review parameter with no default here, on purpose.
112
+ *
113
+ * `require_extra_approval_for_unattributed_changes` is emitted only when the
114
+ * project declares it, and is left out of the payload entirely otherwise. A
115
+ * default of either polarity would be wrong:
116
+ *
117
+ * - `false` would send every repository a loosening it never asked for, and
118
+ * would flip a live `true` off on the next apply;
119
+ * - `true` would send every repository a tightening it never asked for, and
120
+ * would make the negative control below impossible — a project that declares
121
+ * nothing must generate byte-for-byte the payload it generated before this
122
+ * field was declarable.
123
+ *
124
+ * Omission is not neutral either, and that is the finding rather than a
125
+ * shortcoming of this choice. Measured against the live rulesets API on
126
+ * 2026-08-25 (a `pull_request` rule POSTed to a disabled probe ruleset, then
127
+ * PUT three times): omitted, it came back `true`; sent `false`, it came back
128
+ * `false`; sent omitted again, it came back `true` — GitHub resets it to its
129
+ * own default on every write that does not name it. Declaring it is therefore
130
+ * the ONLY way to hold it at `false`, and the only way to record `true` as a
131
+ * choice rather than as whatever GitHub's default happens to be that week.
132
+ */
133
+ const EXTRA_APPROVAL = "require_extra_approval_for_unattributed_changes";
134
+
110
135
  /** Branch-protection defaults, matching the retired template. */
111
136
  export const PROTECT_DEFAULTS = Object.freeze({
112
137
  deletion: true,
@@ -245,6 +270,11 @@ function pullRequestRule(policy) {
245
270
  "conversation_resolution",
246
271
  PROTECT_DEFAULTS
247
272
  ),
273
+ // Spread, not `resolved`, because there is no default to resolve to.
274
+ // See EXTRA_APPROVAL: an undeclared project sends no such key at all.
275
+ ...(policy?.review?.[EXTRA_APPROVAL] === undefined
276
+ ? {}
277
+ : { [EXTRA_APPROVAL]: policy.review[EXTRA_APPROVAL] }),
248
278
  allowed_merge_methods: allowed,
249
279
  },
250
280
  };