@codyswann/lisa 3.62.0 → 3.64.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 (80) hide show
  1. package/all/copy-overwrite/scripts/lisa-gates.mjs +223 -10
  2. package/all/copy-overwrite/scripts/lisa-reconcile-policy.mjs +325 -32
  3. package/dist/cli/gate-report-templates.js +1 -1
  4. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  5. package/dist/core/lisa-owned-hash-ledger.js +8 -0
  6. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  7. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  8. package/dist/core/upstream-evidence-manifest.js +16 -9
  9. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  10. package/dist/health/ruleset-inspection.d.ts.map +1 -1
  11. package/dist/health/ruleset-inspection.js +73 -6
  12. package/dist/health/ruleset-inspection.js.map +1 -1
  13. package/package.json +2 -1
  14. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  16. package/plugins/lisa/.codex-plugin/skills/lisa-doctor/SKILL.md +46 -7
  17. package/plugins/lisa/.codex-plugin/skills/lisa-setup-github-repo/SKILL.md +7 -3
  18. package/plugins/lisa/skills/lisa-doctor/SKILL.md +46 -7
  19. package/plugins/lisa/skills/lisa-setup-github-repo/SKILL.md +7 -3
  20. package/plugins/lisa-agy/plugin.json +1 -1
  21. package/plugins/lisa-agy/skills/lisa-doctor/SKILL.md +46 -7
  22. package/plugins/lisa-agy/skills/lisa-setup-github-repo/SKILL.md +7 -3
  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/skills/lisa-doctor/SKILL.md +46 -7
  30. package/plugins/lisa-copilot/skills/lisa-setup-github-repo/SKILL.md +7 -3
  31. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-cursor/skills/lisa-doctor/SKILL.md +46 -7
  33. package/plugins/lisa-cursor/skills/lisa-setup-github-repo/SKILL.md +7 -3
  34. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  36. package/plugins/lisa-expo-agy/plugin.json +1 -1
  37. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  41. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  42. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  47. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  52. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  57. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  61. package/plugins/lisa-rails-agy/plugin.json +1 -1
  62. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  66. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  67. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  71. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  72. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  74. package/plugins/src/base/skills/lisa-doctor/SKILL.md +46 -7
  75. package/plugins/src/base/skills/lisa-setup-github-repo/SKILL.md +7 -3
  76. package/scripts/check-required-check-promotions.mjs +69 -4
  77. package/scripts/lisa-github-repo-setup.sh +64 -5
  78. package/scripts/lisa-github-rulesets.sh +201 -21
  79. package/scripts/lisa-ruleset-payload.mjs +376 -0
  80. package/all/github-rulesets/base.json +0 -64
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -501,7 +501,11 @@ remedy in that vocabulary removes a required context — the type has no such me
501
501
  guarantee holds for every caller rather than for the careful ones. A surface this run could not
502
502
  read is reported as unproven and is never a match.
503
503
 
504
- The interactive reconciler remains the way to *write* the live ruleset:
504
+ Reconciliation is **wired**, not something an agent has to remember to run: it is step 5 of
505
+ `scripts/lisa-github-repo-setup.sh`, alongside the settings baseline and the rulesets themselves,
506
+ and it is exposed as `npm run policy:reconcile`. Until #2917 its only callers were the code blocks
507
+ below — prose in this very file — so the declared configuration converged when somebody happened to
508
+ read a document. Run it by hand for the flags:
505
509
 
506
510
  ```sh
507
511
  node scripts/lisa-reconcile-policy.mjs --dry-run # read-only: what would change
@@ -529,12 +533,41 @@ drift that was *measured*, and here nothing was. Map it to doctor's `WARN`/`FAIL
529
533
  as any other unavailable check surface: never `PASS`.
530
534
 
531
535
  **2. An `EXTRA` context is reported, never removed.** Lisa does not own the whole required list.
532
- `SonarCloud Code Analysis`, `GitGuardian Security Checks`, and `CodeRabbit` are posted by external
533
- apps that no gates block declares, so `contextsFor` cannot derive them and every one of them is
534
- EXTRA by construction. Under `repair` the script therefore ADDS what is missing and leaves what is
535
- extra alone, naming each one. Removing them requires `--prune`, and the right way to clear the list
536
- is one at a time: each EXTRA context is either an app to keep, or a gate that belongs in
537
- `.lisa.config.json` decide which before pruning anything.
536
+ Under `repair` the script ADDS what is missing and leaves what is extra alone, naming each one.
537
+ Removing them requires `--prune`, and the right way to clear the list is one at a time: each EXTRA
538
+ context is either an app to keep, or a check that belongs in `.lisa.config.json` decide which
539
+ before pruning anything.
540
+
541
+ A context posted by an external app no longer HAS to be EXTRA. `SonarCloud Code Analysis`,
542
+ `GitGuardian Security Checks`, and `CodeRabbit` are declarable two ways, and either one makes the
543
+ reconciler treat them as MATCHED rather than as a permanent false alarm:
544
+
545
+ ```json
546
+ "gates": {
547
+ "credential-leakage": {
548
+ "pull-request": {
549
+ "level": "required",
550
+ "await": "GitGuardian Security Checks",
551
+ "posted_by": 46505
552
+ }
553
+ }
554
+ },
555
+ "github": {
556
+ "rulesets": {
557
+ "requiredChecks": {
558
+ "quality checks": [{ "context": "🧩 Plugin artifacts match source" }]
559
+ }
560
+ }
561
+ }
562
+ ```
563
+
564
+ An `await` names the gate the signal PROVES, so declaring nothing requires nothing — which is how a
565
+ project that proves credential leakage with a different scanner says so. `posted_by` is the GitHub
566
+ App id allowed to post that context; omit it and the context is required unpinned, GitHub's "any
567
+ source". `requiredChecks` is for a repository-specific check that no gate models; it replaces the
568
+ additive-only `addRequiredChecks`, which is still read but can never express "stop requiring this".
569
+ Both surfaces name the ruleset a repair writes to, so `--ruleset` is needed only for a
570
+ gate-DERIVED context on a repository whose rulesets are ambiguous.
538
571
 
539
572
  **3. Keep both names during a rename.** `--previous=<old label>` requires the old and the new
540
573
  context simultaneously for one release. Without it the reconciliation reports the still-live old
@@ -549,6 +582,12 @@ names that script rather than reshaping rules it did not build. When more than o
549
582
  status checks it refuses to guess which owns the derived contexts and asks for `--ruleset=<name>`,
550
583
  because writing to the wrong one enforces a context under a different ref-name condition.
551
584
 
585
+ That rule construction is itself config-driven now. `all/github-rulesets/base.json` is deleted; the
586
+ `base` ruleset is generated per project from `policy` — including `policy.ruleset.enforcement`, the
587
+ `policy.ruleset.include_refs` / `exclude_refs` conditions, `policy.ruleset.bypass_actors`, and
588
+ `policy.review.required_approving_review_count`, none of which config could express while the
589
+ template owned them.
590
+
552
591
  ## Secrets configuration
553
592
 
554
593
  Run the secrets health checks through the skill that owns the contract, rather than reimplementing
@@ -23,12 +23,13 @@ Apply the fleet-standard GitHub repository configuration to this project's repo.
23
23
  - Default branch set to the lowest-tier environment branch that exists (dev → staging → main); override with `github.settings.default_branch`
24
24
  - GitHub wiki tab off (Lisa projects use in-repo `wiki/`)
25
25
  - Secret scanning + push protection enabled where the plan supports it
26
- 2. **Rulesets** (`scripts/lisa-github-rulesets.sh`) from Lisa's `<type>/github-rulesets/` templates, matched by project type:
27
- - `base` — deletion/force-push protection on `main`/`dev`/`staging` + default, PRs required (0 approvals, review-thread resolution required, merge method = merge only), required checks: CodeRabbit + GitGuardian
26
+ 2. **Rulesets** (`scripts/lisa-github-rulesets.sh`) — one generated from config, the rest from Lisa's `<type>/github-rulesets/` templates matched by project type:
27
+ - `base` — **generated from `.lisa.config.json`**, not shipped as a template. Deletion/force-push protection from `policy.protect`, the branch list from `policy.ruleset.include_refs`, bypass actors from `policy.ruleset.bypass_actors`, approvals from `policy.review`, merge methods from `policy.merge`, and required checks from whatever gates the project `await`s. A project that declares nothing gets exactly the ruleset the retired `all/github-rulesets/base.json` described, minus its two vendor checks those are now `await` declarations a project can choose not to make
28
28
  - `quality checks` — the stack's CI checks (TypeScript emoji names or Rails names)
29
29
  - `prevent delete`, `protect tags` (`v*`), plus stack overlays (`cdk validation`, staging-only `playwright`)
30
30
  - Repos without `.github/workflows/` get only app-based required checks — an Actions check that can never report would block every PR forever
31
- - **A template change never reaches an already-configured repo on its own** — re-running this step is the migration. Reconciliation is additive (a live-only required context is preserved, never dropped) and legible: each context the run newly makes blocking is printed as `+ now required: <context>`, and a ruleset that already satisfies its template reports `nothing to do` and is not sent at all, so a second run is visibly a no-op
31
+ - **A template change never reaches an already-configured repo on its own** — re-running this step is the migration. Each context the run newly makes blocking is printed as `+ now required: <context>`, and a ruleset that already satisfies its template reports `nothing to do` and is not sent at all, so a second run is visibly a no-op
32
+ - **Declaring a ruleset's required list makes it declarative.** By default a live-only required context is preserved, never dropped — including on the generated `base`, which gets no exemption: removing a protection by default, on a script invoked with `--yes`, is not something an operator ever opted into. Name a ruleset in `github.rulesets.requiredChecks` and the live list stops being unioned in, so removing an entry actually stops requiring it — printed as `- no longer required: <context>`. Dropping an `await` without that opt-in leaves the live context in place; `lisa-reconcile-policy.mjs` then reports it as EXTRA, and `--prune` is where the removal is asked for. The retired `addRequiredChecks` is still read and could only ever add
32
33
  3. **Deploy key** (`scripts/setup-deploy-key.sh --yes`) — write-access deploy key + `DEPLOY_KEY` secret, skipped when already configured. The `base` ruleset's `DeployKey: always` bypass is what lets CI version-bump pushes through protected branches.
33
34
  4. **Deployment environments** (`scripts/lisa-github-environments.sh`) — entirely optional; only runs when `.lisa.config.json` declares environments:
34
35
  ```json
@@ -52,6 +53,9 @@ Apply the fleet-standard GitHub repository configuration to this project's repo.
52
53
  - Every declared environment also gets a **deployment branch policy** pinned to its branch, so only that branch can deploy to it.
53
54
  - Provisioning matters: GitHub silently auto-creates an environment **without** protection rules the first time a workflow references it, so an unprovisioned approval gate gates on nothing.
54
55
  - The stack `deploy.yml` templates read this same config at runtime and pass `require_approval`/`approval_environment` to `release.yml`, whose `release_approval` job is where the run pauses. Requires a public repo or a paid plan for private repos (the script skips gracefully otherwise).
56
+ 5. **Policy reconciliation** (`scripts/lisa-reconcile-policy.mjs`, also `npm run policy:reconcile`) — compares the DECLARED gates and `policy` block against what GitHub actually has, and converges it when `policy.on_drift` is `repair`. It runs here rather than only from a skill file, because a declaration nothing applies is not governance.
57
+ - The installed `scripts/lisa-reconcile-policy.mjs` is preferred; the shipped template is the fallback; finding neither is a hard failure, not a skip.
58
+ - Exit `2` is `UNPROVEN` — `gh` refused, is missing, or answered something unparseable. A private repository on a plan without rulesets answers `403`. Setup **warns and continues**: failing for a plan limitation punishes a repository that has done nothing wrong. The warning names the state, because a blind gate that says nothing is indistinguishable from a clean one.
55
59
 
56
60
  ## Workflow
57
61
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -501,7 +501,11 @@ remedy in that vocabulary removes a required context — the type has no such me
501
501
  guarantee holds for every caller rather than for the careful ones. A surface this run could not
502
502
  read is reported as unproven and is never a match.
503
503
 
504
- The interactive reconciler remains the way to *write* the live ruleset:
504
+ Reconciliation is **wired**, not something an agent has to remember to run: it is step 5 of
505
+ `scripts/lisa-github-repo-setup.sh`, alongside the settings baseline and the rulesets themselves,
506
+ and it is exposed as `npm run policy:reconcile`. Until #2917 its only callers were the code blocks
507
+ below — prose in this very file — so the declared configuration converged when somebody happened to
508
+ read a document. Run it by hand for the flags:
505
509
 
506
510
  ```sh
507
511
  node scripts/lisa-reconcile-policy.mjs --dry-run # read-only: what would change
@@ -529,12 +533,41 @@ drift that was *measured*, and here nothing was. Map it to doctor's `WARN`/`FAIL
529
533
  as any other unavailable check surface: never `PASS`.
530
534
 
531
535
  **2. An `EXTRA` context is reported, never removed.** Lisa does not own the whole required list.
532
- `SonarCloud Code Analysis`, `GitGuardian Security Checks`, and `CodeRabbit` are posted by external
533
- apps that no gates block declares, so `contextsFor` cannot derive them and every one of them is
534
- EXTRA by construction. Under `repair` the script therefore ADDS what is missing and leaves what is
535
- extra alone, naming each one. Removing them requires `--prune`, and the right way to clear the list
536
- is one at a time: each EXTRA context is either an app to keep, or a gate that belongs in
537
- `.lisa.config.json` decide which before pruning anything.
536
+ Under `repair` the script ADDS what is missing and leaves what is extra alone, naming each one.
537
+ Removing them requires `--prune`, and the right way to clear the list is one at a time: each EXTRA
538
+ context is either an app to keep, or a check that belongs in `.lisa.config.json` decide which
539
+ before pruning anything.
540
+
541
+ A context posted by an external app no longer HAS to be EXTRA. `SonarCloud Code Analysis`,
542
+ `GitGuardian Security Checks`, and `CodeRabbit` are declarable two ways, and either one makes the
543
+ reconciler treat them as MATCHED rather than as a permanent false alarm:
544
+
545
+ ```json
546
+ "gates": {
547
+ "credential-leakage": {
548
+ "pull-request": {
549
+ "level": "required",
550
+ "await": "GitGuardian Security Checks",
551
+ "posted_by": 46505
552
+ }
553
+ }
554
+ },
555
+ "github": {
556
+ "rulesets": {
557
+ "requiredChecks": {
558
+ "quality checks": [{ "context": "🧩 Plugin artifacts match source" }]
559
+ }
560
+ }
561
+ }
562
+ ```
563
+
564
+ An `await` names the gate the signal PROVES, so declaring nothing requires nothing — which is how a
565
+ project that proves credential leakage with a different scanner says so. `posted_by` is the GitHub
566
+ App id allowed to post that context; omit it and the context is required unpinned, GitHub's "any
567
+ source". `requiredChecks` is for a repository-specific check that no gate models; it replaces the
568
+ additive-only `addRequiredChecks`, which is still read but can never express "stop requiring this".
569
+ Both surfaces name the ruleset a repair writes to, so `--ruleset` is needed only for a
570
+ gate-DERIVED context on a repository whose rulesets are ambiguous.
538
571
 
539
572
  **3. Keep both names during a rename.** `--previous=<old label>` requires the old and the new
540
573
  context simultaneously for one release. Without it the reconciliation reports the still-live old
@@ -549,6 +582,12 @@ names that script rather than reshaping rules it did not build. When more than o
549
582
  status checks it refuses to guess which owns the derived contexts and asks for `--ruleset=<name>`,
550
583
  because writing to the wrong one enforces a context under a different ref-name condition.
551
584
 
585
+ That rule construction is itself config-driven now. `all/github-rulesets/base.json` is deleted; the
586
+ `base` ruleset is generated per project from `policy` — including `policy.ruleset.enforcement`, the
587
+ `policy.ruleset.include_refs` / `exclude_refs` conditions, `policy.ruleset.bypass_actors`, and
588
+ `policy.review.required_approving_review_count`, none of which config could express while the
589
+ template owned them.
590
+
552
591
  ## Secrets configuration
553
592
 
554
593
  Run the secrets health checks through the skill that owns the contract, rather than reimplementing
@@ -23,12 +23,13 @@ Apply the fleet-standard GitHub repository configuration to this project's repo.
23
23
  - Default branch set to the lowest-tier environment branch that exists (dev → staging → main); override with `github.settings.default_branch`
24
24
  - GitHub wiki tab off (Lisa projects use in-repo `wiki/`)
25
25
  - Secret scanning + push protection enabled where the plan supports it
26
- 2. **Rulesets** (`scripts/lisa-github-rulesets.sh`) from Lisa's `<type>/github-rulesets/` templates, matched by project type:
27
- - `base` — deletion/force-push protection on `main`/`dev`/`staging` + default, PRs required (0 approvals, review-thread resolution required, merge method = merge only), required checks: CodeRabbit + GitGuardian
26
+ 2. **Rulesets** (`scripts/lisa-github-rulesets.sh`) — one generated from config, the rest from Lisa's `<type>/github-rulesets/` templates matched by project type:
27
+ - `base` — **generated from `.lisa.config.json`**, not shipped as a template. Deletion/force-push protection from `policy.protect`, the branch list from `policy.ruleset.include_refs`, bypass actors from `policy.ruleset.bypass_actors`, approvals from `policy.review`, merge methods from `policy.merge`, and required checks from whatever gates the project `await`s. A project that declares nothing gets exactly the ruleset the retired `all/github-rulesets/base.json` described, minus its two vendor checks those are now `await` declarations a project can choose not to make
28
28
  - `quality checks` — the stack's CI checks (TypeScript emoji names or Rails names)
29
29
  - `prevent delete`, `protect tags` (`v*`), plus stack overlays (`cdk validation`, staging-only `playwright`)
30
30
  - Repos without `.github/workflows/` get only app-based required checks — an Actions check that can never report would block every PR forever
31
- - **A template change never reaches an already-configured repo on its own** — re-running this step is the migration. Reconciliation is additive (a live-only required context is preserved, never dropped) and legible: each context the run newly makes blocking is printed as `+ now required: <context>`, and a ruleset that already satisfies its template reports `nothing to do` and is not sent at all, so a second run is visibly a no-op
31
+ - **A template change never reaches an already-configured repo on its own** — re-running this step is the migration. Each context the run newly makes blocking is printed as `+ now required: <context>`, and a ruleset that already satisfies its template reports `nothing to do` and is not sent at all, so a second run is visibly a no-op
32
+ - **Declaring a ruleset's required list makes it declarative.** By default a live-only required context is preserved, never dropped — including on the generated `base`, which gets no exemption: removing a protection by default, on a script invoked with `--yes`, is not something an operator ever opted into. Name a ruleset in `github.rulesets.requiredChecks` and the live list stops being unioned in, so removing an entry actually stops requiring it — printed as `- no longer required: <context>`. Dropping an `await` without that opt-in leaves the live context in place; `lisa-reconcile-policy.mjs` then reports it as EXTRA, and `--prune` is where the removal is asked for. The retired `addRequiredChecks` is still read and could only ever add
32
33
  3. **Deploy key** (`scripts/setup-deploy-key.sh --yes`) — write-access deploy key + `DEPLOY_KEY` secret, skipped when already configured. The `base` ruleset's `DeployKey: always` bypass is what lets CI version-bump pushes through protected branches.
33
34
  4. **Deployment environments** (`scripts/lisa-github-environments.sh`) — entirely optional; only runs when `.lisa.config.json` declares environments:
34
35
  ```json
@@ -52,6 +53,9 @@ Apply the fleet-standard GitHub repository configuration to this project's repo.
52
53
  - Every declared environment also gets a **deployment branch policy** pinned to its branch, so only that branch can deploy to it.
53
54
  - Provisioning matters: GitHub silently auto-creates an environment **without** protection rules the first time a workflow references it, so an unprovisioned approval gate gates on nothing.
54
55
  - The stack `deploy.yml` templates read this same config at runtime and pass `require_approval`/`approval_environment` to `release.yml`, whose `release_approval` job is where the run pauses. Requires a public repo or a paid plan for private repos (the script skips gracefully otherwise).
56
+ 5. **Policy reconciliation** (`scripts/lisa-reconcile-policy.mjs`, also `npm run policy:reconcile`) — compares the DECLARED gates and `policy` block against what GitHub actually has, and converges it when `policy.on_drift` is `repair`. It runs here rather than only from a skill file, because a declaration nothing applies is not governance.
57
+ - The installed `scripts/lisa-reconcile-policy.mjs` is preferred; the shipped template is the fallback; finding neither is a hard failure, not a skip.
58
+ - Exit `2` is `UNPROVEN` — `gh` refused, is missing, or answered something unparseable. A private repository on a plan without rulesets answers `403`. Setup **warns and continues**: failing for a plan limitation punishes a repository that has done nothing wrong. The warning names the state, because a blind gate that says nothing is indistinguishable from a clean one.
55
59
 
56
60
  ## Workflow
57
61
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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": "3.62.0",
3
+ "version": "3.64.0",
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"