@codyswann/lisa 4.34.8 → 4.34.9

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 (67) hide show
  1. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  2. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  3. package/dist/core/upstream-evidence-manifest.js +3 -2
  4. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  5. package/package.json +4 -4
  6. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  7. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  8. package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +141 -1
  9. package/plugins/lisa/.codex-plugin/skills/lisa-git-submit-pr/SKILL.md +2 -0
  10. package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +141 -1
  11. package/plugins/lisa/skills/lisa-git-submit-pr/SKILL.md +2 -0
  12. package/plugins/lisa-agy/plugin.json +1 -1
  13. package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +141 -1
  14. package/plugins/lisa-agy/skills/lisa-git-submit-pr/SKILL.md +2 -0
  15. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  16. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  18. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +141 -1
  22. package/plugins/lisa-copilot/skills/lisa-git-submit-pr/SKILL.md +2 -0
  23. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +141 -1
  25. package/plugins/lisa-cursor/skills/lisa-git-submit-pr/SKILL.md +2 -0
  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-agy/plugin.json +1 -1
  29. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  38. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  39. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  43. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  44. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  48. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  49. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  53. package/plugins/lisa-rails-agy/plugin.json +1 -1
  54. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  58. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  59. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  63. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  64. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  66. package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +141 -1
  67. package/plugins/src/base/skills/lisa-git-submit-pr/SKILL.md +2 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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.34.8",
3
+ "version": "4.34.9",
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"
@@ -41,6 +41,11 @@ merges" loop. Other skills delegate here instead of re-implementing it. Runs
41
41
  green, open, un-merged PR is the *success* outcome of this mode, not a hang.
42
42
  Used by learning-persistence flows whose low-confidence PRs must wait for a
43
43
  human (`lisa-persist-learning`).
44
+
45
+ **`auto_merge` is caller-time and nothing re-reads it.** That is what the hold
46
+ label (section 0) exists for: the same behaviour, raisable by anyone at any
47
+ point while the loop runs. Both routes land in `awaiting-human`; they differ
48
+ only in who can take them and when.
44
49
  - `on_blocker=<fix|report>` — what to do when a blocker needs code or review work.
45
50
  Default `fix`.
46
51
  - **`fix`** (the full loop): resolve conflicts, fix failing checks, address +
@@ -97,9 +102,115 @@ gh pr edit <pr> --add-label "lisa:babysitter-on-duty"
97
102
  closed, or a hard block handed to a human. A crashed session that never
98
103
  releases is why the TTL exists; do not rely on it as the normal release path.
99
104
 
105
+ ### The hold gate — a stop anyone can raise
106
+
107
+ Section 0 owns this skill's two PR labels: the lease it **writes** to declare
108
+ ownership, and the hold it **reads** to be told to stop. Same mechanism, pointed
109
+ at different things — a lease is a claim, a hold is a decision.
110
+
111
+ **The label** is `lisa:hold` by default, overridable per project at
112
+ `github.labels.merge.hold`, resolved local-over-global like every other
113
+ configured name. Resolve it ONCE at startup and reuse the resolved string; a
114
+ name re-resolved each iteration can change identity mid-loop for no reason a
115
+ reader could reconstruct afterwards.
116
+
117
+ ```bash
118
+ HOLD_LABEL=$(
119
+ jq -r 'first(.github.labels.merge.hold | strings)' \
120
+ .lisa.config.local.json .lisa.config.json 2>/dev/null | head -n1
121
+ )
122
+ HOLD_LABEL="${HOLD_LABEL:-lisa:hold}"
123
+ ```
124
+
125
+ **What it means:** exactly `auto_merge=false`, for as long as it is present. Not
126
+ a new concept and not a new terminal state — the same disarm, the same
127
+ fail-closed re-read, the same `awaiting-human` landing. The only new surface is
128
+ one label read.
129
+
130
+ **Why it exists.** `auto_merge` is decided by the caller at invocation, and
131
+ nothing re-reads it, so the only person who can stop the merge is the person who
132
+ started it. Anyone else — a reviewer who opens the PR while the loop is driving
133
+ it, someone holding a PR another session armed — has no lever and loses the
134
+ race. Measured (#3558): four explicit `gh pr merge --disable-auto` calls were
135
+ each followed by a re-arm 7–25 seconds later, and the PR merged two seconds
136
+ after its final check went green. **The hold did not fail; it lost a race.** A
137
+ signal the loop itself reads cannot be raced, because the loop is what reads it.
138
+
139
+ #### Evaluate it in two places, and re-read it every iteration
140
+
141
+ - **Before arming** (section 1) — a PR already carrying the label is never armed.
142
+ - **On every watch-loop iteration** (section 2), before acting on any blocker.
143
+
144
+ Re-reading is the entire point. A check that runs once at startup is a
145
+ caller-time signal wearing a loop's clothing and fixes nothing, because the case
146
+ that matters is a label applied **after** the loop is already running. If you
147
+ are changing this and it is convenient to read the label once, you have
148
+ reintroduced the defect.
149
+
150
+ ```bash
151
+ gh pr view <pr> --json labels --jq "[.labels[].name] | index(\"$HOLD_LABEL\") != null"
152
+ ```
153
+
154
+ **Match the resolved name exactly — never a prefix.** `lisa:babysitter-on-duty`
155
+ is a label this skill applies to itself and shares the `lisa:` prefix; a
156
+ prefix match would make the loop stop on its own lease, which is a deadlock
157
+ that looks like a human decision.
158
+
159
+ #### When held
160
+
161
+ 1. Run the existing `auto_merge=false` disarm (section 1) — disable the latch
162
+ once and prove with the fail-closed re-read that it took.
163
+ 2. Return `awaiting-human:held` (section 4).
164
+ 3. **Do not remove the label.** Removing a human's signal is unrecoverable from
165
+ inside the loop; leaving a stale one costs a cycle and is visible. Only
166
+ whoever applied it takes it off, and a later invocation then resumes normally.
167
+
168
+ Do not keep polling while held. Held is terminal for this run, not a pause to
169
+ wait out — the loop has been told a human is looking, and continuing to drive is
170
+ the behaviour the label exists to stop.
171
+
172
+ **The disarm is once and terminal: never re-arm the latch afterwards, and never
173
+ resume driving in the same run.** This is what keeps a hold compatible with the
174
+ armed-across-fix-pushes rule in section 1, which otherwise forbids disarming on
175
+ the `auto_merge=true` path. That rule exists to prevent a *race* — disarm, then
176
+ re-arm, repeatedly, while still driving — and a hold does neither half of it: it
177
+ turns the latch off exactly once and then stops. A hold that re-armed, or that
178
+ kept driving afterwards, would be the race that rule names, wearing a label.
179
+
180
+ #### When the read fails
181
+
182
+ **Fail toward hold.** The asymmetry decides it: a false hold costs one cycle and
183
+ is visible in a terminal report someone can act on, while a false no-hold merges
184
+ past a human's objection and cannot be undone. Where the two errors are
185
+ unequal, take the recoverable one.
186
+
187
+ But a read that keeps failing must not become a silent deadlock, so the failure
188
+ is **reported as its own outcome** rather than dressed up as a decision:
189
+
190
+ - retry the read once;
191
+ - if it still fails, disarm as above and return **`awaiting-human:hold-unknown`**,
192
+ naming the error.
193
+
194
+ `awaiting-human:held` and `awaiting-human:hold-unknown` are different facts and
195
+ an operator needs to know which: the first says *a human stopped this*, the
196
+ second says *I could not tell whether a human stopped this.* Collapsing them
197
+ would hide a broken permission behind a human decision, and nobody would ever
198
+ look.
199
+
200
+ **A PR with no hold label is driven exactly as it is today.** This gate adds a
201
+ stop; it does not add a block. If the label is absent and the read succeeded,
202
+ nothing about the run changes.
203
+
100
204
  ## 1. Enable auto-merge
101
205
 
102
- **Gate: only when `auto_merge=true` (the default).** When `auto_merge=false`,
206
+ **Gate: the hold label is absent (section 0's hold gate), and `auto_merge=true`
207
+ (the default).** Evaluate the hold gate BEFORE anything in this section,
208
+ including the arm gate below and the direct-merge capability fallback: a held PR
209
+ is not armed, not merged directly, and not driven — it disarms once and returns
210
+ `awaiting-human:held`. Checking after arming would authorise the merge the label
211
+ exists to prevent, which is the same ordering error the arm gate itself fixes.
212
+
213
+ When `auto_merge=false`,
103
214
  skip the enable step and its capability fallback — do not enable auto-merge,
104
215
  and do **not** use the capability fallback below: on a repo that disallows
105
216
  auto-merge, an `auto_merge=false` PR must stay OPEN for human triage, never be
@@ -357,6 +468,12 @@ Poll the live state each iteration:
357
468
  gh pr view <pr> --json state,mergeStateStatus,mergeable,reviewDecision,statusCheckRollup,headRefName,baseRefName
358
469
  ```
359
470
 
471
+ **Re-read the hold label on every iteration, before handling any blocker**
472
+ (section 0's hold gate). It is polled separately from the line above rather than
473
+ folded into it, because `labels` is not part of the blocker state: the hold is a
474
+ question about whether to keep going at all, asked before the blocker questions,
475
+ and a run that answers it once at startup has not implemented it.
476
+
360
477
  Handle every blocker class; after any fix, re-poll and continue. Do not stop while
361
478
  the PR is still open and progress is possible. On each iteration, refresh the
362
479
  babysitter lease if its last stamp is older than ~30 minutes (section 0).
@@ -393,6 +510,13 @@ and return per the input contract above. That includes (f): adjudicating a pendi
393
510
  auto-fix PR (merging, closing, or deleting its branch) is destructive work, not
394
511
  diagnosis — return its classification (`blocked:pending-auto-fix`) instead.
395
512
 
513
+ **The hold gate binds in report mode too**, and it binds first: a held PR
514
+ returns `awaiting-human:held` without arming, without the mechanical step (a)
515
+ nudge, and without an `update-branch`. Hold is not a blocker classification and
516
+ never returns as one — `blocked:*` says *this PR cannot proceed yet*, while a
517
+ hold says *someone asked me not to proceed*, and reporting the second as the
518
+ first would file a human's decision as a defect for something else to clear.
519
+
396
520
  The arm gate binds in report mode too, and this is the mode where forgetting it
397
521
  does the most damage: a diagnose-only run that arms the latch has not diagnosed
398
522
  anything, it has authorised a merge. Under a vacuous review context, report mode
@@ -938,6 +1062,22 @@ Loop until one of:
938
1062
  merge but nobody reviewed it: the review tool says it skips public
939
1063
  repositories, and that will not change on its own. Merge it yourself or ask
940
1064
  for a human review."*
1065
+ - **`awaiting-human:held`** → success, and the only terminal state a person can
1066
+ cause on purpose from outside the run. The hold label (section 0) was present,
1067
+ the latch was disarmed once and the re-read proved it, and the label was left
1068
+ in place. Report the PR URL, the resolved label name, and that removing the
1069
+ label lets a later invocation resume — for example: *"PR #123 is on hold:
1070
+ someone added the `lisa:hold` label, so I stopped instead of merging it.
1071
+ Remove that label when you want it to continue."* Not a stall and not a
1072
+ failure: a human asked for the PR to stop, and it stopped.
1073
+ - **`awaiting-human:hold-unknown`** → the hold label could not be read (twice),
1074
+ so whether a human asked for a stop is **unknown**. The latch is disarmed and
1075
+ the PR sits OPEN, on the fail-toward-hold rule in section 0. Report the read
1076
+ error verbatim. This is deliberately NOT reported as `awaiting-human:held`:
1077
+ that would file a broken permission or a rate limit as a human decision, and
1078
+ the one thing nobody would then do is investigate it. Usually a missing
1079
+ `issues: read` / label-read permission, which is fixable and invisible from
1080
+ the merge outcome alone.
941
1081
  - **`CLOSED`** → report (PR was closed without merge).
942
1082
  - **Hard block needing a human**: an unresolvable conflict, a failing check that
943
1083
  needs design input, or genuine unresolved human objection (not a bot gate). Stop
@@ -48,6 +48,8 @@ Recognized optional hints:
48
48
 
49
49
  This delegation is now load-bearing rather than a convenience: it is the only path that arms auto-merge, so skipping it leaves the PR open rather than quietly merging it. Reporting submission as complete without invoking it is a failed submit, not a partial one — say so instead of implying the PR is on its way to merged.
50
50
 
51
+ **The hold label needs no check here, and adding one would be dead code.** `drive-pr-to-merge` evaluates its hold gate before it arms anything, so a PR created with the label already on it is never armed — by the delegation, not by a second check in this skill. That guarantee used to require one: while step 5 armed the latch at creation, a hold that covered only the loop left the creation-time arm wide open, which is why CodySwannGT/lisa#3558 asked for a check in both places. Step 5 no longer arms, so there is nothing here for a label to gate. If you are adding one because the ticket says to, re-read step 5 first.
52
+
51
53
  ### Native Development Linkage
52
54
 
53
55
  Add provider-appropriate linkage to the PR title and/or body without changing the status lifecycle: