@codyswann/lisa 2.292.0 → 2.293.1

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 (71) hide show
  1. package/all/copy-overwrite/scripts/lisa-work-item.mjs +76 -6
  2. package/dist/core/upstream-evidence-manifest.js +4 -4
  3. package/dist/opencode/plugin-templates/parity-safety-net.sh +41 -0
  4. package/package.json +1 -1
  5. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  6. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  7. package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +1 -1
  8. package/plugins/lisa/.codex-plugin/skills/lisa-parity-safety-net-rules/SKILL.md +16 -11
  9. package/plugins/lisa/hooks/parity-safety-net.sh +41 -0
  10. package/plugins/lisa/skills/lisa-implement/SKILL.md +1 -1
  11. package/plugins/lisa/skills/lisa-parity-safety-net-rules/SKILL.md +16 -11
  12. package/plugins/lisa-agy/hooks/parity-safety-net.sh +41 -0
  13. package/plugins/lisa-agy/plugin.json +1 -1
  14. package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +1 -1
  15. package/plugins/lisa-agy/skills/lisa-parity-safety-net-rules/SKILL.md +16 -11
  16. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  19. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-copilot/hooks/parity-safety-net.sh +41 -0
  23. package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +1 -1
  24. package/plugins/lisa-copilot/skills/lisa-parity-safety-net-rules/SKILL.md +16 -11
  25. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-cursor/hooks/parity-safety-net.sh +41 -0
  27. package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +1 -1
  28. package/plugins/lisa-cursor/skills/lisa-parity-safety-net-rules/SKILL.md +16 -11
  29. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  31. package/plugins/lisa-expo-agy/plugin.json +1 -1
  32. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  37. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  41. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  42. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  47. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  52. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-rails-agy/plugin.json +1 -1
  57. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  61. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  62. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  66. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  67. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  69. package/plugins/src/base/hooks/parity-safety-net.sh +41 -0
  70. package/plugins/src/base/skills/lisa-implement/SKILL.md +1 -1
  71. package/plugins/src/base/skills/lisa-parity-safety-net-rules/SKILL.md +16 -11
@@ -76,6 +76,26 @@ function currentBranch() {
76
76
  return git(["branch", "--show-current"]);
77
77
  }
78
78
 
79
+ /**
80
+ * Branch an in-progress rebase is rewriting, or empty when no rebase is in
81
+ * progress. During a rebase HEAD is detached, but git records the branch being
82
+ * rebased in `<rebase-state-dir>/head-name` (issue #1956) — resolved via
83
+ * `git rev-parse --git-path` so linked worktrees find their private state dir.
84
+ */
85
+ function rebaseBranch() {
86
+ for (const stateDir of ["rebase-merge", "rebase-apply"]) {
87
+ const file = resolve(
88
+ git(["rev-parse", "--git-path", `${stateDir}/head-name`])
89
+ );
90
+ if (!existsSync(file)) continue;
91
+ const headName = readFileSync(file, "utf8").trim();
92
+ if (headName.startsWith("refs/heads/")) {
93
+ return headName.slice("refs/heads/".length);
94
+ }
95
+ }
96
+ return "";
97
+ }
98
+
79
99
  function deepMerge(base, override) {
80
100
  if (Array.isArray(base) || Array.isArray(override)) return override;
81
101
  if (
@@ -301,7 +321,11 @@ function readState(optional = true) {
301
321
  }
302
322
 
303
323
  function assertStateBranch(state) {
304
- const branch = currentBranch();
324
+ // Mid-rebase HEAD is detached, but the binding must validate against the
325
+ // branch the rebase is rewriting (its head-name) so rebase picks and
326
+ // `git rebase --continue` commits are not wedged (issue #1956). A detached
327
+ // HEAD with NO rebase in progress still fails closed below.
328
+ const branch = currentBranch() || rebaseBranch();
305
329
  if (!branch)
306
330
  throw new TrackingError(
307
331
  "Cannot use a work-item binding from detached HEAD"
@@ -402,15 +426,24 @@ function namesFrom(value) {
402
426
  }
403
427
 
404
428
  function assertRepoScope(ref, contract, labels, components = []) {
405
- const expected = `repo:${contract.identityRepo}`.toLowerCase();
429
+ // #1957: mirror the intake-side scoping rule uniformly across trackers
430
+ // (plugins/lisa/rules/reference/config-resolution.md:949,:968): a work item
431
+ // is repo-scoped by the label `repo:<name>` OR the bare `<name>` label
432
+ // (Sentry-provenance items carry only the bare repo name). The match is the
433
+ // exact repo short name, case-insensitive via namesFrom's lowercasing —
434
+ // never substring or prefix. Jira additionally accepts a component equal to
435
+ // the bare name.
436
+ const bare = contract.identityRepo.toLowerCase();
437
+ const expected = `repo:${bare}`;
406
438
  const labelNames = namesFrom(labels);
407
439
  const componentNames = namesFrom(components);
408
440
  if (
409
441
  !labelNames.includes(expected) &&
410
- !componentNames.includes(contract.identityRepo.toLowerCase())
442
+ !labelNames.includes(bare) &&
443
+ !componentNames.includes(bare)
411
444
  ) {
412
445
  throw new TrackingError(
413
- `Work item ${ref} is not scoped to repository ${contract.identityRepo}; require label ${expected}`
446
+ `Work item ${ref} is not scoped to repository ${contract.identityRepo}; require label ${expected} or bare label ${bare}`
414
447
  );
415
448
  }
416
449
  }
@@ -888,15 +921,52 @@ function validateCommits(commits) {
888
921
  };
889
922
  }
890
923
 
924
+ /**
925
+ * Fully qualified remote default-branch ref (e.g. refs/remotes/origin/main),
926
+ * or undefined when it cannot be resolved offline. Reads the LOCAL
927
+ * `refs/remotes/<remote>/HEAD` symref only — never the network. Resolution
928
+ * failure means the exclusion is skipped (fail-safe strict, issue #1956).
929
+ * Security: only the remote DEFAULT branch is ever excluded — never
930
+ * `--remotes=<remote>`, whose ref set includes the branch being (force-)pushed
931
+ * and would let a pusher exempt arbitrary commits.
932
+ */
933
+ function remoteDefaultRef(remote) {
934
+ const symref = run(
935
+ "git",
936
+ ["symbolic-ref", "--quiet", `refs/remotes/${remote}/HEAD`],
937
+ { allowFailure: true }
938
+ );
939
+ if (symref.status !== 0) return undefined;
940
+ const target = symref.stdout.trim();
941
+ if (!target.startsWith(`refs/remotes/${remote}/`)) return undefined;
942
+ const exists = run("git", ["rev-parse", "-q", "--verify", target], {
943
+ allowFailure: true,
944
+ });
945
+ return exists.status === 0 ? target : undefined;
946
+ }
947
+
891
948
  function parsePushLines(input, remote) {
892
949
  const commits = [];
950
+ // Commits already reachable from the remote default branch are the base's
951
+ // history (a merge-sync brings them along); excluding them keeps validation
952
+ // scoped to branch-authored commits (issue #1956).
953
+ const defaultRef = remoteDefaultRef(remote);
893
954
  for (const line of input.trim().split(/\r?\n/).filter(Boolean)) {
894
955
  const [, localOid, , remoteOid] = line.trim().split(/\s+/);
895
956
  if (!localOid || ZERO_OID.test(localOid)) continue;
896
957
  const args =
897
958
  remoteOid && !ZERO_OID.test(remoteOid)
898
- ? ["rev-list", `${remoteOid}..${localOid}`]
899
- : ["rev-list", localOid, "--not", `--remotes=${remote}`];
959
+ ? [
960
+ "rev-list",
961
+ `${remoteOid}..${localOid}`,
962
+ ...(defaultRef ? ["--not", defaultRef] : []),
963
+ ]
964
+ : // New-branch lane: `--remotes=<remote>` is safe HERE because the branch
965
+ // being pushed has no remote-tracking ref yet — the exclusion set can
966
+ // only contain refs that already passed validation on earlier pushes.
967
+ // The existing-branch lane above must NOT use it (its tracking ref is
968
+ // pusher-controlled); it excludes only the remote default branch.
969
+ ["rev-list", localOid, "--not", `--remotes=${remote}`];
900
970
  commits.push(...git(args).split("\n").filter(Boolean));
901
971
  }
902
972
  if (commits.length === 0 && input.trim() === "") {
@@ -2,7 +2,7 @@
2
2
  /** Generated by scripts/generate-upstream-evidence-manifest.mjs. Do not edit. */
3
3
  export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
4
4
  "all/copy-contents/gitignore": "06b56376465d5421db55d0b04958bbc79fdbf33b42f0559fe5ef6875ced1160f",
5
- "all/copy-overwrite/scripts/lisa-work-item.mjs": "4c263fef48c03b3b6c623ea8a6cd55505bfaf28197e5072226ea35f9f3d26885",
5
+ "all/copy-overwrite/scripts/lisa-work-item.mjs": "5eb31c284e820a51312d4484f0669128007326af55ee515923fec33700d003a1",
6
6
  "all/create-only/.claude/rules/PROJECT_RULES.md": "6e1c7923ad2a15356babc60c97e7f97be728d790af285b6a7cd7d1b4d39cd97f",
7
7
  "all/create-only/.lisaignore": "3c9827e7e98daa46510b5357cd6dd9406da1821e64cc46d2eea9f311cd6d06b9",
8
8
  "all/create-only/scripts/remote-agent-aws-setup.sh": "7677908a345891810d2104ba8b2fd1a8318bb29c408fb5ce0110d57beef9b556",
@@ -294,7 +294,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
294
294
  "plugins/src/base/hooks/install-pkgs.sh": "e9a13faba849a277410dde911ab102ee6f88ef915b33571bb1d4eef904172db5",
295
295
  "plugins/src/base/hooks/parity-safety-net-heredoc.py": "c5301958ed8ca29b0de7b8521d299cdbc8c1c402df8d8fada6b5f173b6cf5dbe",
296
296
  "plugins/src/base/hooks/parity-safety-net.agy.sh": "ce9bd2b4566ad9147e4ace56434cffbbe87edb4ccbb57549ab3fd9f4c671ced4",
297
- "plugins/src/base/hooks/parity-safety-net.sh": "64546813f168fb446f39e34bc674fd3af85b15bd5e7f4f6bf4503463e701a7b9",
297
+ "plugins/src/base/hooks/parity-safety-net.sh": "b83c5043a0f29b2d8851258acfe6906aab7922cd80f486e25220e55f26a8c0a5",
298
298
  "plugins/src/base/hooks/setup-jira-cli.sh": "a675f6b17ce7f0d6b9fb7daeba6d2bc59bcb48ef79b034076ea73b2b1e72ee09",
299
299
  "plugins/src/base/hooks/shell-write-nudge.sh": "69839af423f8792b1e52c71097316c3264425553031627c0a2f9409a9d5becd0",
300
300
  "plugins/src/base/hooks/threshold-ratchet-compare.mjs": "8bc4b379d7057b2fecf9cb35820c39efad0a65df7df49073786f996cc2a74810",
@@ -426,7 +426,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
426
426
  "plugins/src/base/skills/lisa-github-write-issue/SKILL.md": "ee54b3d14cc5dd3a68a8c36590102dd02f49334c9493ad52fa8c7f35157073b1",
427
427
  "plugins/src/base/skills/lisa-github-write-prd/SKILL.md": "bc919c52e2f42129d41a3f40279d2def99486ec58bed2dab51ca7166b427a947",
428
428
  "plugins/src/base/skills/lisa-health/SKILL.md": "dfdb08a863e78bff42671793dcec29cfae0654db18ebf66a4aa77aeb56ddb775",
429
- "plugins/src/base/skills/lisa-implement/SKILL.md": "6271b8c4dd34efb630020a63e03d8df813d4faccb81517dfb3637ef2433d968d",
429
+ "plugins/src/base/skills/lisa-implement/SKILL.md": "cb3a0587907321301e6662480af0d333aee4a3e0d29e9bdc851c225be2c220d7",
430
430
  "plugins/src/base/skills/lisa-improve-code-complexity/SKILL.md": "24ab5b193b409db6ee6bee981a1c0a48d08991782d7846116ad01658c8bc1ae8",
431
431
  "plugins/src/base/skills/lisa-improve-harness/SKILL.md": "bafda5d2f9b86c48cd16bf0015528fdf5891675221d662fdc533aaad66aad669",
432
432
  "plugins/src/base/skills/lisa-improve-max-lines-per-function/SKILL.md": "95c875950c9848fdaf520a18b9bbb264e33d7347be10170add768e01d9cd8e52",
@@ -480,7 +480,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
480
480
  "plugins/src/base/skills/lisa-parity-code-review/SKILL.md": "5805254747c4ed9081fd514236f06e078be86d41694bf74b480bf7592cd58c1f",
481
481
  "plugins/src/base/skills/lisa-parity-code-simplifier/SKILL.md": "c721ae772e73abff633c43d93267066afac188e911a77322fbb102db673849d7",
482
482
  "plugins/src/base/skills/lisa-parity-coderabbit/SKILL.md": "ae882837d43741293d1b639c4516331fa6124fa1f5da234a74ecb31c5d7e52cd",
483
- "plugins/src/base/skills/lisa-parity-safety-net-rules/SKILL.md": "d338796d10498bd660c36f7f66c6b5be54cf7e281d19b9df44b0d2a01e398b68",
483
+ "plugins/src/base/skills/lisa-parity-safety-net-rules/SKILL.md": "2515b016f3a1c80163aaf097c3f530e884e59e2070d072a6cb5c7b9d2658c946",
484
484
  "plugins/src/base/skills/lisa-parity-sentry-sdk-setup/SKILL.md": "ed52b0273f6b535d26d561c80ae6c0bedb84c67fcf4321f688c05fe3ee3af575",
485
485
  "plugins/src/base/skills/lisa-parity-sentry-seer/SKILL.md": "f44216fa7c8f0c3c3371c65ff73bbeadd1717579502a5603f16b3b33291cab7a",
486
486
  "plugins/src/base/skills/lisa-parity-skill-creator/SKILL.md": "616e0493f75fe92c18137548d7c86a91a9b04d9844ca76fa3f14156e3e7814e5",
@@ -24,6 +24,11 @@
24
24
  # divergence: upstream blocks unconditionally; Lisa allows clean-tree resets.
25
25
  # Residual risk (documented, accepted): the dirty check runs in the hook's
26
26
  # cwd at hook time, so a `cd elsewhere && git reset --hard` evades it.
27
+ # - `git rebase --abort`/`--quit` while the in-progress rebase holds
28
+ # human-made conflict resolutions (AUTO_MERGE discriminator; issue #1956).
29
+ # Clean or untouched rebase state stays abortable; the apply backend and a
30
+ # missing AUTO_MERGE ref fail closed. Deliberate divergence: upstream
31
+ # blocks `rebase --abort` unconditionally, which strands agents mid-rebase.
27
32
  # - `git checkout` discards (`--`, `-f/--force`, `--pathspec-from-file`,
28
33
  # bare `.` — the bare-`.` block exceeds upstream)
29
34
  # - `git switch --discard-changes` / `-f/--force`
@@ -312,6 +317,42 @@ if matches "${GIT_CMD}"'reset\b.*--(hard|merge)\b'; then
312
317
  fi
313
318
  fi
314
319
 
320
+ # 3b. `git rebase --abort` / `--quit` ONLY while human/agent conflict
321
+ # resolutions exist (issue #1956). `--abort` restores the pre-rebase branch
322
+ # and discards every resolution; `--quit` deletes the rebase bookkeeping
323
+ # (head-name, todo) while stranding a detached HEAD, making recovery
324
+ # ambiguous — both are treated the same, conditionally. A rebase state with
325
+ # nothing human-made in it (a clean-pick wedge, or a conflict stop nobody
326
+ # has touched) is agent-recoverable, so aborting it stays ALLOWED.
327
+ # Discriminator (empirical, git 2.53): diff the worktree/index against the
328
+ # AUTO_MERGE ref (the merge-ort recorded conflicted tree). Abort-safe ⇔
329
+ # worktree diff is quiet AND (the cached diff is quiet OR unmerged index
330
+ # entries exist — an untouched conflict stop has unmerged entries that make
331
+ # the cached diff non-quiet without any human edit). Fail CLOSED on the
332
+ # rebase-apply backend (no AUTO_MERGE contract) and on a missing AUTO_MERGE
333
+ # ref while rebase-merge state exists. Same accepted residual risk as
334
+ # guard 3: the probes run in the hook's cwd at hook time.
335
+ if matches "${GIT_CMD}"'rebase'"${GIT_TOKENS}"'--(abort|quit)([[:space:]]|$)'; then
336
+ rebase_apply_dir="$(git rev-parse --git-path rebase-apply 2>/dev/null || true)"
337
+ rebase_merge_dir="$(git rev-parse --git-path rebase-merge 2>/dev/null || true)"
338
+ if [ -n "$rebase_apply_dir" ] && [ -d "$rebase_apply_dir" ]; then
339
+ block "git rebase --abort/--quit on an apply-backend rebase cannot prove no conflict resolutions would be lost (fail closed; finish or continue the rebase instead)"
340
+ fi
341
+ if [ -n "$rebase_merge_dir" ] && [ -d "$rebase_merge_dir" ]; then
342
+ if ! git rev-parse -q --verify AUTO_MERGE >/dev/null 2>&1; then
343
+ block "git rebase --abort/--quit with an unresolvable AUTO_MERGE ref cannot prove no conflict resolutions would be lost (fail closed)"
344
+ fi
345
+ if ! git diff --quiet AUTO_MERGE 2>/dev/null; then
346
+ block "git rebase --abort/--quit would discard conflict resolutions in the working tree (finish resolving and run git rebase --continue instead)"
347
+ fi
348
+ unmerged_entries="$(git ls-files -u 2>/dev/null || true)"
349
+ if [ -z "$unmerged_entries" ] \
350
+ && ! git diff --cached --quiet AUTO_MERGE 2>/dev/null; then
351
+ block "git rebase --abort/--quit would discard staged conflict resolutions (finish resolving and run git rebase --continue instead)"
352
+ fi
353
+ fi
354
+ fi
355
+
315
356
  # 4. `git checkout` worktree discards: the `--` pathspec form (with or without a
316
357
  # ref), `-f/--force`, `--pathspec-from-file`, and bare `git checkout .`.
317
358
  # Blocking bare `.` exceeds upstream (which allows any single positional) —
package/package.json CHANGED
@@ -113,7 +113,7 @@
113
113
  "brace-expansion": ">=5.0.6"
114
114
  },
115
115
  "name": "@codyswann/lisa",
116
- "version": "2.292.0",
116
+ "version": "2.293.1",
117
117
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
118
118
  "main": "dist/index.js",
119
119
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.292.0",
3
+ "version": "2.293.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.292.0",
3
+ "version": "2.293.1",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -95,7 +95,7 @@ Using the general-purpose agent in Team Lead session, **determine the base branc
95
95
  - Already on a feature branch with an **open PR** → reuse it. If the PR's base ≠ the resolved base branch, surface the mismatch and re-target only with confirmation — the ticket's environment is the source of truth.
96
96
  - Already on a feature branch with **no open PR** → reuse it; its PR base will be the resolved base branch (do not ask the human — the environment determines it).
97
97
  - On an **environment / default branch** → check out a feature branch named for this plan (with the work-item ref prefix, per the linkage rules below) **from `origin/<base>`**.
98
- - **Rebase the feature branch onto `origin/<base>` and resolve any merge conflicts BEFORE starting work.** If the conflicts cannot be resolved cleanly and safely, create a fix task for the agent team (with the conflicting file list and current merge state) and resolve it before implementation begins — never start work on stale or conflicted code.
98
+ - **Sync the feature branch onto the latest `origin/<base>` and resolve any merge conflicts BEFORE starting work.** Both sync lanes are sanctioned in a bound worktree: **rebase** (`git rebase origin/<base>` — the commit hooks validate mid-rebase picks against the rebase head-name, so a work-item binding never wedges a rebase) and **merge** (`git merge origin/<base>` — push validation exempts commits already reachable from the remote default branch, while branch-authored commits stay strictly validated; the exemption needs the local `origin/HEAD` symref, so if a hand-added remote fails push validation on foreign commits, run `git remote set-head origin -a` first). Prefer rebase for a linear history; use merge when rewriting pushed history is undesirable. If a rebase goes wrong before anyone has resolved conflicts, `git rebase --abort` is a safe, allowed recovery; once conflict resolutions exist, the safety net blocks abort to protect them — finish resolving and `git rebase --continue` instead. If the conflicts cannot be resolved cleanly and safely, create a fix task for the agent team (with the conflicting file list and current merge state) and resolve it before implementation begins — never start work on stale or conflicted code.
99
99
  4. **The PR targets the resolved base branch** — carry it as `target_branch=<base>` into `lisa-git-submit-pr` (Verify flow). `git-submit-pr` already chooses a closing keyword when the base is the production/default branch and a non-closing reference for a non-terminal environment branch. For a bug fixed on a non-integration environment branch, the current flow is not done until the fix is merged and verified there, then forward cherry-picked down to the integration branch via a linked follow-up.
100
100
 
101
101
  Every Implement run now has a tracker work item. Preserve its canonical identifier for development linkage unconditionally:
@@ -69,22 +69,27 @@ RULES_FILE="${SAFETY_NET_RULES_FILE:-${CLAUDE_PROJECT_DIR:-$PWD}/.claude/safety-
69
69
  (`git push origin +main`) is not blocked — upstream 1.0.6 allows it too.
70
70
  4. `git reset --hard` / `git reset --merge` while the working tree is **dirty**
71
71
  (would discard work). Clean-tree resets are intentionally allowed.
72
- 5. `git checkout` discards: the `--` pathspec form (with or without a ref),
72
+ 5. `git rebase --abort` / `git rebase --quit` while the in-progress rebase
73
+ holds human-made conflict resolutions (they would be discarded). A clean or
74
+ untouched rebase state stays abortable — an agent-recoverable wedge; the
75
+ apply backend and a missing `AUTO_MERGE` ref fail closed. Deliberate
76
+ divergence: upstream blocks `rebase --abort` unconditionally.
77
+ 6. `git checkout` discards: the `--` pathspec form (with or without a ref),
73
78
  `-f`/`--force`, `--pathspec-from-file`, and bare `git checkout .`.
74
79
  Branch switching and `-b`/`-B` creation stay allowed.
75
- 6. `git switch --discard-changes` / `-f`/`--force`.
76
- 7. `git restore` touching the worktree — only `git restore --staged <path>`
80
+ 7. `git switch --discard-changes` / `-f`/`--force`.
81
+ 8. `git restore` touching the worktree — only `git restore --staged <path>`
77
82
  without `--worktree` is allowed (unstaging is safe).
78
- 8. `git stash drop` / `git stash clear` (push/pop/list/apply stay allowed).
79
- 9. `git clean` with a force flag and no dry-run — `-n`/`--dry-run` anywhere
80
- makes it a safe preview.
81
- 10. `git branch -D` (or `-d` combined with `-f`, clustered or split);
83
+ 9. `git stash drop` / `git stash clear` (push/pop/list/apply stay allowed).
84
+ 10. `git clean` with a force flag and no dry-run — `-n`/`--dry-run` anywhere
85
+ makes it a safe preview.
86
+ 11. `git branch -D` (or `-d` combined with `-f`, clustered or split);
82
87
  safe `-d` and rename `-m` stay allowed.
83
- 11. `git tag -d`, `git reflog delete`, `git worktree remove --force`.
84
- 12. Deletion via `find … -delete`, `find … -exec rm -rf`, and `xargs … rm -rf`
88
+ 12. `git tag -d`, `git reflog delete`, `git worktree remove --force`.
89
+ 13. Deletion via `find … -delete`, `find … -exec rm -rf`, and `xargs … rm -rf`
85
90
  (plain non-recursive `rm` on find/xargs output stays allowed).
86
- 13. Disk destroyers: `dd of=/dev/…`, `mkfs … /dev/…`, `shred`.
87
- 14. Destructive SQL — `DROP DATABASE/SCHEMA/TABLE`, `TRUNCATE TABLE`.
91
+ 14. Disk destroyers: `dd of=/dev/…`, `mkfs … /dev/…`, `shred`.
92
+ 15. Destructive SQL — `DROP DATABASE/SCHEMA/TABLE`, `TRUNCATE TABLE`.
88
93
 
89
94
  Every git guard sees through leading git **global options** (`-C <path>`,
90
95
  `-c <k>=<v>`, `--git-dir[=…]`, `--no-pager`, …), so `git -C /path <destructive>`
@@ -24,6 +24,11 @@
24
24
  # divergence: upstream blocks unconditionally; Lisa allows clean-tree resets.
25
25
  # Residual risk (documented, accepted): the dirty check runs in the hook's
26
26
  # cwd at hook time, so a `cd elsewhere && git reset --hard` evades it.
27
+ # - `git rebase --abort`/`--quit` while the in-progress rebase holds
28
+ # human-made conflict resolutions (AUTO_MERGE discriminator; issue #1956).
29
+ # Clean or untouched rebase state stays abortable; the apply backend and a
30
+ # missing AUTO_MERGE ref fail closed. Deliberate divergence: upstream
31
+ # blocks `rebase --abort` unconditionally, which strands agents mid-rebase.
27
32
  # - `git checkout` discards (`--`, `-f/--force`, `--pathspec-from-file`,
28
33
  # bare `.` — the bare-`.` block exceeds upstream)
29
34
  # - `git switch --discard-changes` / `-f/--force`
@@ -312,6 +317,42 @@ if matches "${GIT_CMD}"'reset\b.*--(hard|merge)\b'; then
312
317
  fi
313
318
  fi
314
319
 
320
+ # 3b. `git rebase --abort` / `--quit` ONLY while human/agent conflict
321
+ # resolutions exist (issue #1956). `--abort` restores the pre-rebase branch
322
+ # and discards every resolution; `--quit` deletes the rebase bookkeeping
323
+ # (head-name, todo) while stranding a detached HEAD, making recovery
324
+ # ambiguous — both are treated the same, conditionally. A rebase state with
325
+ # nothing human-made in it (a clean-pick wedge, or a conflict stop nobody
326
+ # has touched) is agent-recoverable, so aborting it stays ALLOWED.
327
+ # Discriminator (empirical, git 2.53): diff the worktree/index against the
328
+ # AUTO_MERGE ref (the merge-ort recorded conflicted tree). Abort-safe ⇔
329
+ # worktree diff is quiet AND (the cached diff is quiet OR unmerged index
330
+ # entries exist — an untouched conflict stop has unmerged entries that make
331
+ # the cached diff non-quiet without any human edit). Fail CLOSED on the
332
+ # rebase-apply backend (no AUTO_MERGE contract) and on a missing AUTO_MERGE
333
+ # ref while rebase-merge state exists. Same accepted residual risk as
334
+ # guard 3: the probes run in the hook's cwd at hook time.
335
+ if matches "${GIT_CMD}"'rebase'"${GIT_TOKENS}"'--(abort|quit)([[:space:]]|$)'; then
336
+ rebase_apply_dir="$(git rev-parse --git-path rebase-apply 2>/dev/null || true)"
337
+ rebase_merge_dir="$(git rev-parse --git-path rebase-merge 2>/dev/null || true)"
338
+ if [ -n "$rebase_apply_dir" ] && [ -d "$rebase_apply_dir" ]; then
339
+ block "git rebase --abort/--quit on an apply-backend rebase cannot prove no conflict resolutions would be lost (fail closed; finish or continue the rebase instead)"
340
+ fi
341
+ if [ -n "$rebase_merge_dir" ] && [ -d "$rebase_merge_dir" ]; then
342
+ if ! git rev-parse -q --verify AUTO_MERGE >/dev/null 2>&1; then
343
+ block "git rebase --abort/--quit with an unresolvable AUTO_MERGE ref cannot prove no conflict resolutions would be lost (fail closed)"
344
+ fi
345
+ if ! git diff --quiet AUTO_MERGE 2>/dev/null; then
346
+ block "git rebase --abort/--quit would discard conflict resolutions in the working tree (finish resolving and run git rebase --continue instead)"
347
+ fi
348
+ unmerged_entries="$(git ls-files -u 2>/dev/null || true)"
349
+ if [ -z "$unmerged_entries" ] \
350
+ && ! git diff --cached --quiet AUTO_MERGE 2>/dev/null; then
351
+ block "git rebase --abort/--quit would discard staged conflict resolutions (finish resolving and run git rebase --continue instead)"
352
+ fi
353
+ fi
354
+ fi
355
+
315
356
  # 4. `git checkout` worktree discards: the `--` pathspec form (with or without a
316
357
  # ref), `-f/--force`, `--pathspec-from-file`, and bare `git checkout .`.
317
358
  # Blocking bare `.` exceeds upstream (which allows any single positional) —
@@ -95,7 +95,7 @@ Using the general-purpose agent in Team Lead session, **determine the base branc
95
95
  - Already on a feature branch with an **open PR** → reuse it. If the PR's base ≠ the resolved base branch, surface the mismatch and re-target only with confirmation — the ticket's environment is the source of truth.
96
96
  - Already on a feature branch with **no open PR** → reuse it; its PR base will be the resolved base branch (do not ask the human — the environment determines it).
97
97
  - On an **environment / default branch** → check out a feature branch named for this plan (with the work-item ref prefix, per the linkage rules below) **from `origin/<base>`**.
98
- - **Rebase the feature branch onto `origin/<base>` and resolve any merge conflicts BEFORE starting work.** If the conflicts cannot be resolved cleanly and safely, create a fix task for the agent team (with the conflicting file list and current merge state) and resolve it before implementation begins — never start work on stale or conflicted code.
98
+ - **Sync the feature branch onto the latest `origin/<base>` and resolve any merge conflicts BEFORE starting work.** Both sync lanes are sanctioned in a bound worktree: **rebase** (`git rebase origin/<base>` — the commit hooks validate mid-rebase picks against the rebase head-name, so a work-item binding never wedges a rebase) and **merge** (`git merge origin/<base>` — push validation exempts commits already reachable from the remote default branch, while branch-authored commits stay strictly validated; the exemption needs the local `origin/HEAD` symref, so if a hand-added remote fails push validation on foreign commits, run `git remote set-head origin -a` first). Prefer rebase for a linear history; use merge when rewriting pushed history is undesirable. If a rebase goes wrong before anyone has resolved conflicts, `git rebase --abort` is a safe, allowed recovery; once conflict resolutions exist, the safety net blocks abort to protect them — finish resolving and `git rebase --continue` instead. If the conflicts cannot be resolved cleanly and safely, create a fix task for the agent team (with the conflicting file list and current merge state) and resolve it before implementation begins — never start work on stale or conflicted code.
99
99
  4. **The PR targets the resolved base branch** — carry it as `target_branch=<base>` into `lisa-git-submit-pr` (Verify flow). `git-submit-pr` already chooses a closing keyword when the base is the production/default branch and a non-closing reference for a non-terminal environment branch. For a bug fixed on a non-integration environment branch, the current flow is not done until the fix is merged and verified there, then forward cherry-picked down to the integration branch via a linked follow-up.
100
100
 
101
101
  Every Implement run now has a tracker work item. Preserve its canonical identifier for development linkage unconditionally:
@@ -69,22 +69,27 @@ RULES_FILE="${SAFETY_NET_RULES_FILE:-${CLAUDE_PROJECT_DIR:-$PWD}/.claude/safety-
69
69
  (`git push origin +main`) is not blocked — upstream 1.0.6 allows it too.
70
70
  4. `git reset --hard` / `git reset --merge` while the working tree is **dirty**
71
71
  (would discard work). Clean-tree resets are intentionally allowed.
72
- 5. `git checkout` discards: the `--` pathspec form (with or without a ref),
72
+ 5. `git rebase --abort` / `git rebase --quit` while the in-progress rebase
73
+ holds human-made conflict resolutions (they would be discarded). A clean or
74
+ untouched rebase state stays abortable — an agent-recoverable wedge; the
75
+ apply backend and a missing `AUTO_MERGE` ref fail closed. Deliberate
76
+ divergence: upstream blocks `rebase --abort` unconditionally.
77
+ 6. `git checkout` discards: the `--` pathspec form (with or without a ref),
73
78
  `-f`/`--force`, `--pathspec-from-file`, and bare `git checkout .`.
74
79
  Branch switching and `-b`/`-B` creation stay allowed.
75
- 6. `git switch --discard-changes` / `-f`/`--force`.
76
- 7. `git restore` touching the worktree — only `git restore --staged <path>`
80
+ 7. `git switch --discard-changes` / `-f`/`--force`.
81
+ 8. `git restore` touching the worktree — only `git restore --staged <path>`
77
82
  without `--worktree` is allowed (unstaging is safe).
78
- 8. `git stash drop` / `git stash clear` (push/pop/list/apply stay allowed).
79
- 9. `git clean` with a force flag and no dry-run — `-n`/`--dry-run` anywhere
80
- makes it a safe preview.
81
- 10. `git branch -D` (or `-d` combined with `-f`, clustered or split);
83
+ 9. `git stash drop` / `git stash clear` (push/pop/list/apply stay allowed).
84
+ 10. `git clean` with a force flag and no dry-run — `-n`/`--dry-run` anywhere
85
+ makes it a safe preview.
86
+ 11. `git branch -D` (or `-d` combined with `-f`, clustered or split);
82
87
  safe `-d` and rename `-m` stay allowed.
83
- 11. `git tag -d`, `git reflog delete`, `git worktree remove --force`.
84
- 12. Deletion via `find … -delete`, `find … -exec rm -rf`, and `xargs … rm -rf`
88
+ 12. `git tag -d`, `git reflog delete`, `git worktree remove --force`.
89
+ 13. Deletion via `find … -delete`, `find … -exec rm -rf`, and `xargs … rm -rf`
85
90
  (plain non-recursive `rm` on find/xargs output stays allowed).
86
- 13. Disk destroyers: `dd of=/dev/…`, `mkfs … /dev/…`, `shred`.
87
- 14. Destructive SQL — `DROP DATABASE/SCHEMA/TABLE`, `TRUNCATE TABLE`.
91
+ 14. Disk destroyers: `dd of=/dev/…`, `mkfs … /dev/…`, `shred`.
92
+ 15. Destructive SQL — `DROP DATABASE/SCHEMA/TABLE`, `TRUNCATE TABLE`.
88
93
 
89
94
  Every git guard sees through leading git **global options** (`-C <path>`,
90
95
  `-c <k>=<v>`, `--git-dir[=…]`, `--no-pager`, …), so `git -C /path <destructive>`
@@ -24,6 +24,11 @@
24
24
  # divergence: upstream blocks unconditionally; Lisa allows clean-tree resets.
25
25
  # Residual risk (documented, accepted): the dirty check runs in the hook's
26
26
  # cwd at hook time, so a `cd elsewhere && git reset --hard` evades it.
27
+ # - `git rebase --abort`/`--quit` while the in-progress rebase holds
28
+ # human-made conflict resolutions (AUTO_MERGE discriminator; issue #1956).
29
+ # Clean or untouched rebase state stays abortable; the apply backend and a
30
+ # missing AUTO_MERGE ref fail closed. Deliberate divergence: upstream
31
+ # blocks `rebase --abort` unconditionally, which strands agents mid-rebase.
27
32
  # - `git checkout` discards (`--`, `-f/--force`, `--pathspec-from-file`,
28
33
  # bare `.` — the bare-`.` block exceeds upstream)
29
34
  # - `git switch --discard-changes` / `-f/--force`
@@ -312,6 +317,42 @@ if matches "${GIT_CMD}"'reset\b.*--(hard|merge)\b'; then
312
317
  fi
313
318
  fi
314
319
 
320
+ # 3b. `git rebase --abort` / `--quit` ONLY while human/agent conflict
321
+ # resolutions exist (issue #1956). `--abort` restores the pre-rebase branch
322
+ # and discards every resolution; `--quit` deletes the rebase bookkeeping
323
+ # (head-name, todo) while stranding a detached HEAD, making recovery
324
+ # ambiguous — both are treated the same, conditionally. A rebase state with
325
+ # nothing human-made in it (a clean-pick wedge, or a conflict stop nobody
326
+ # has touched) is agent-recoverable, so aborting it stays ALLOWED.
327
+ # Discriminator (empirical, git 2.53): diff the worktree/index against the
328
+ # AUTO_MERGE ref (the merge-ort recorded conflicted tree). Abort-safe ⇔
329
+ # worktree diff is quiet AND (the cached diff is quiet OR unmerged index
330
+ # entries exist — an untouched conflict stop has unmerged entries that make
331
+ # the cached diff non-quiet without any human edit). Fail CLOSED on the
332
+ # rebase-apply backend (no AUTO_MERGE contract) and on a missing AUTO_MERGE
333
+ # ref while rebase-merge state exists. Same accepted residual risk as
334
+ # guard 3: the probes run in the hook's cwd at hook time.
335
+ if matches "${GIT_CMD}"'rebase'"${GIT_TOKENS}"'--(abort|quit)([[:space:]]|$)'; then
336
+ rebase_apply_dir="$(git rev-parse --git-path rebase-apply 2>/dev/null || true)"
337
+ rebase_merge_dir="$(git rev-parse --git-path rebase-merge 2>/dev/null || true)"
338
+ if [ -n "$rebase_apply_dir" ] && [ -d "$rebase_apply_dir" ]; then
339
+ block "git rebase --abort/--quit on an apply-backend rebase cannot prove no conflict resolutions would be lost (fail closed; finish or continue the rebase instead)"
340
+ fi
341
+ if [ -n "$rebase_merge_dir" ] && [ -d "$rebase_merge_dir" ]; then
342
+ if ! git rev-parse -q --verify AUTO_MERGE >/dev/null 2>&1; then
343
+ block "git rebase --abort/--quit with an unresolvable AUTO_MERGE ref cannot prove no conflict resolutions would be lost (fail closed)"
344
+ fi
345
+ if ! git diff --quiet AUTO_MERGE 2>/dev/null; then
346
+ block "git rebase --abort/--quit would discard conflict resolutions in the working tree (finish resolving and run git rebase --continue instead)"
347
+ fi
348
+ unmerged_entries="$(git ls-files -u 2>/dev/null || true)"
349
+ if [ -z "$unmerged_entries" ] \
350
+ && ! git diff --cached --quiet AUTO_MERGE 2>/dev/null; then
351
+ block "git rebase --abort/--quit would discard staged conflict resolutions (finish resolving and run git rebase --continue instead)"
352
+ fi
353
+ fi
354
+ fi
355
+
315
356
  # 4. `git checkout` worktree discards: the `--` pathspec form (with or without a
316
357
  # ref), `-f/--force`, `--pathspec-from-file`, and bare `git checkout .`.
317
358
  # Blocking bare `.` exceeds upstream (which allows any single positional) —
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.292.0",
3
+ "version": "2.293.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -95,7 +95,7 @@ Using the general-purpose agent in Team Lead session, **determine the base branc
95
95
  - Already on a feature branch with an **open PR** → reuse it. If the PR's base ≠ the resolved base branch, surface the mismatch and re-target only with confirmation — the ticket's environment is the source of truth.
96
96
  - Already on a feature branch with **no open PR** → reuse it; its PR base will be the resolved base branch (do not ask the human — the environment determines it).
97
97
  - On an **environment / default branch** → check out a feature branch named for this plan (with the work-item ref prefix, per the linkage rules below) **from `origin/<base>`**.
98
- - **Rebase the feature branch onto `origin/<base>` and resolve any merge conflicts BEFORE starting work.** If the conflicts cannot be resolved cleanly and safely, create a fix task for the agent team (with the conflicting file list and current merge state) and resolve it before implementation begins — never start work on stale or conflicted code.
98
+ - **Sync the feature branch onto the latest `origin/<base>` and resolve any merge conflicts BEFORE starting work.** Both sync lanes are sanctioned in a bound worktree: **rebase** (`git rebase origin/<base>` — the commit hooks validate mid-rebase picks against the rebase head-name, so a work-item binding never wedges a rebase) and **merge** (`git merge origin/<base>` — push validation exempts commits already reachable from the remote default branch, while branch-authored commits stay strictly validated; the exemption needs the local `origin/HEAD` symref, so if a hand-added remote fails push validation on foreign commits, run `git remote set-head origin -a` first). Prefer rebase for a linear history; use merge when rewriting pushed history is undesirable. If a rebase goes wrong before anyone has resolved conflicts, `git rebase --abort` is a safe, allowed recovery; once conflict resolutions exist, the safety net blocks abort to protect them — finish resolving and `git rebase --continue` instead. If the conflicts cannot be resolved cleanly and safely, create a fix task for the agent team (with the conflicting file list and current merge state) and resolve it before implementation begins — never start work on stale or conflicted code.
99
99
  4. **The PR targets the resolved base branch** — carry it as `target_branch=<base>` into `lisa-git-submit-pr` (Verify flow). `git-submit-pr` already chooses a closing keyword when the base is the production/default branch and a non-closing reference for a non-terminal environment branch. For a bug fixed on a non-integration environment branch, the current flow is not done until the fix is merged and verified there, then forward cherry-picked down to the integration branch via a linked follow-up.
100
100
 
101
101
  Every Implement run now has a tracker work item. Preserve its canonical identifier for development linkage unconditionally:
@@ -69,22 +69,27 @@ RULES_FILE="${SAFETY_NET_RULES_FILE:-${CLAUDE_PROJECT_DIR:-$PWD}/.claude/safety-
69
69
  (`git push origin +main`) is not blocked — upstream 1.0.6 allows it too.
70
70
  4. `git reset --hard` / `git reset --merge` while the working tree is **dirty**
71
71
  (would discard work). Clean-tree resets are intentionally allowed.
72
- 5. `git checkout` discards: the `--` pathspec form (with or without a ref),
72
+ 5. `git rebase --abort` / `git rebase --quit` while the in-progress rebase
73
+ holds human-made conflict resolutions (they would be discarded). A clean or
74
+ untouched rebase state stays abortable — an agent-recoverable wedge; the
75
+ apply backend and a missing `AUTO_MERGE` ref fail closed. Deliberate
76
+ divergence: upstream blocks `rebase --abort` unconditionally.
77
+ 6. `git checkout` discards: the `--` pathspec form (with or without a ref),
73
78
  `-f`/`--force`, `--pathspec-from-file`, and bare `git checkout .`.
74
79
  Branch switching and `-b`/`-B` creation stay allowed.
75
- 6. `git switch --discard-changes` / `-f`/`--force`.
76
- 7. `git restore` touching the worktree — only `git restore --staged <path>`
80
+ 7. `git switch --discard-changes` / `-f`/`--force`.
81
+ 8. `git restore` touching the worktree — only `git restore --staged <path>`
77
82
  without `--worktree` is allowed (unstaging is safe).
78
- 8. `git stash drop` / `git stash clear` (push/pop/list/apply stay allowed).
79
- 9. `git clean` with a force flag and no dry-run — `-n`/`--dry-run` anywhere
80
- makes it a safe preview.
81
- 10. `git branch -D` (or `-d` combined with `-f`, clustered or split);
83
+ 9. `git stash drop` / `git stash clear` (push/pop/list/apply stay allowed).
84
+ 10. `git clean` with a force flag and no dry-run — `-n`/`--dry-run` anywhere
85
+ makes it a safe preview.
86
+ 11. `git branch -D` (or `-d` combined with `-f`, clustered or split);
82
87
  safe `-d` and rename `-m` stay allowed.
83
- 11. `git tag -d`, `git reflog delete`, `git worktree remove --force`.
84
- 12. Deletion via `find … -delete`, `find … -exec rm -rf`, and `xargs … rm -rf`
88
+ 12. `git tag -d`, `git reflog delete`, `git worktree remove --force`.
89
+ 13. Deletion via `find … -delete`, `find … -exec rm -rf`, and `xargs … rm -rf`
85
90
  (plain non-recursive `rm` on find/xargs output stays allowed).
86
- 13. Disk destroyers: `dd of=/dev/…`, `mkfs … /dev/…`, `shred`.
87
- 14. Destructive SQL — `DROP DATABASE/SCHEMA/TABLE`, `TRUNCATE TABLE`.
91
+ 14. Disk destroyers: `dd of=/dev/…`, `mkfs … /dev/…`, `shred`.
92
+ 15. Destructive SQL — `DROP DATABASE/SCHEMA/TABLE`, `TRUNCATE TABLE`.
88
93
 
89
94
  Every git guard sees through leading git **global options** (`-C <path>`,
90
95
  `-c <k>=<v>`, `--git-dir[=…]`, `--no-pager`, …), so `git -C /path <destructive>`
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "2.292.0",
3
+ "version": "2.293.1",
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": "2.292.0",
3
+ "version": "2.293.1",
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": "2.292.0",
3
+ "version": "2.293.1",
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": "2.292.0",
3
+ "version": "2.293.1",
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": "2.292.0",
3
+ "version": "2.293.1",
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": "2.292.0",
3
+ "version": "2.293.1",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"