@codyswann/lisa 4.65.7 → 4.66.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 (65) hide show
  1. package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.mjs +34 -10
  2. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  3. package/dist/core/lisa-owned-hash-ledger.js +8 -0
  4. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  5. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  6. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  7. package/dist/core/upstream-evidence-manifest.js +7 -4
  8. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  9. package/expo/copy-overwrite/eslint.expo.ts +2 -2
  10. package/expo/create-only/.github/workflows/maestro-e2e.yml +6 -0
  11. package/package.json +4 -4
  12. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  14. package/plugins/lisa/hooks/worktree-binding-guard.mjs +34 -10
  15. package/plugins/lisa-agy/plugin.json +1 -1
  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/worktree-binding-guard.mjs +34 -10
  23. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-cursor/hooks/worktree-binding-guard.mjs +34 -10
  25. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  27. package/plugins/lisa-expo-agy/plugin.json +1 -1
  28. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  35. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  38. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  43. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  47. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  48. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-rails-agy/plugin.json +1 -1
  53. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  58. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  63. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/src/base/hooks/worktree-binding-guard.mjs +34 -10
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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": "4.65.7",
3
+ "version": "4.66.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"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.65.7",
3
+ "version": "4.66.0",
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.65.7",
3
+ "version": "4.66.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"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.65.7",
3
+ "version": "4.66.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"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.65.7",
3
+ "version": "4.66.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"
@@ -503,9 +503,32 @@ function reachesOut(script, foreign, bound) {
503
503
  ]);
504
504
  }
505
505
 
506
- function stateFile(sessionId) {
506
+ function stateFile(bindingKey) {
507
507
  const home = process.env.LISA_STATE_HOME || join(homedir(), ".lisa");
508
- return join(home, "worktree-binding", `${sessionId}.json`);
508
+ return join(home, "worktree-binding", `${bindingKey}.json`);
509
+ }
510
+
511
+ /**
512
+ * The identity a binding belongs to.
513
+ *
514
+ * Parallel subagents share the session's `session_id`, so keying the binding
515
+ * on it alone made each subagent's guarded call read the binding a sibling
516
+ * recorded — the sibling's worktree then read as "changed underneath it" and
517
+ * its writes were refused, or an acknowledgement rebound the file out from
518
+ * under the sibling (CodySwannGT/lisa#4277). The payload's `agent_id` is what
519
+ * distinguishes a subagent from the main agent, so a caller carrying one gets
520
+ * its own state file. The main agent carries no `agent_id` and keeps the
521
+ * session-scoped key it always had, which is also the fallback for runtimes
522
+ * that never send the field.
523
+ *
524
+ * The key lands in a filename, so the composite is folded into a set that is
525
+ * legal on every filesystem — `:` is not, which rules it out as a separator
526
+ * and as tolerated session_id content on Windows hosts.
527
+ */
528
+ function bindingKey(payload) {
529
+ const agent = payload?.agent_id;
530
+ if (typeof agent !== "string" || !agent) return payload.session_id;
531
+ return `${payload.session_id}--${agent}`.replaceAll(/[^A-Za-z0-9._-]/g, "_");
509
532
  }
510
533
 
511
534
  function readState(sessionId) {
@@ -637,8 +660,8 @@ function recordBaseline(sessionId, observed) {
637
660
  function recordClaim(payload, observed) {
638
661
  const claimed = claimedRoot(payload.tool_input, payload.cwd);
639
662
  if (!claimed || claimed === observed) return;
640
- const previous = readState(payload.session_id);
641
- writeState(payload.session_id, {
663
+ const previous = readState(bindingKey(payload));
664
+ writeState(bindingKey(payload), {
642
665
  boundRoot: previous?.boundRoot ?? observed,
643
666
  claimedRoot: claimed,
644
667
  updatedAt: new Date().toISOString(),
@@ -678,7 +701,7 @@ function handleAcceptance(payload, observed) {
678
701
  acceptanceLine(observed),
679
702
  ]);
680
703
  }
681
- writeState(payload.session_id, {
704
+ writeState(bindingKey(payload), {
682
705
  boundRoot: observed,
683
706
  claimedRoot: null,
684
707
  updatedAt: new Date().toISOString(),
@@ -880,15 +903,16 @@ function evaluate(payload) {
880
903
  say("payload carries no session id or cwd; binding is NOT enforced");
881
904
  return 0;
882
905
  }
906
+ const binding = bindingKey(payload);
883
907
  const observed = worktreeRoot(cwd);
884
908
  if (!observed) return 0;
885
909
 
886
910
  if (payload.hook_event_name === "SessionStart") {
887
- recordBaseline(sessionId, observed);
911
+ recordBaseline(binding, observed);
888
912
  // After the baseline, never before: `recordBaseline` writes a fresh state
889
913
  // for a session it has not seen, and the notice's record has to go on top
890
914
  // of that write rather than under it.
891
- noticeRuntimeDrift(sessionId, process.env);
915
+ noticeRuntimeDrift(binding, process.env);
892
916
  return 0;
893
917
  }
894
918
  if (payload.tool_name === "EnterWorktree") {
@@ -900,7 +924,7 @@ function evaluate(payload) {
900
924
  const accepted = handleAcceptance(payload, observed);
901
925
  if (accepted !== null) return accepted;
902
926
 
903
- const state = readState(sessionId);
927
+ const state = readState(binding);
904
928
  if (!state?.boundRoot) {
905
929
  // No baseline means SessionStart did not run for this session — an older
906
930
  // install, a runtime that fires no such event, a harness that skips it.
@@ -909,7 +933,7 @@ function evaluate(payload) {
909
933
  // refusing. Treating it as a refusal would turn a floor into a wall on
910
934
  // every surface where the event does not fire, and a wall gets switched
911
935
  // off, which costs the whole guard.
912
- writeState(sessionId, {
936
+ writeState(binding, {
913
937
  boundRoot: observed,
914
938
  claimedRoot: null,
915
939
  updatedAt: new Date().toISOString(),
@@ -920,7 +944,7 @@ function evaluate(payload) {
920
944
  return unconfirmedSwitch(state.claimedRoot, observed);
921
945
  }
922
946
  if (state.claimedRoot === observed) {
923
- writeState(sessionId, {
947
+ writeState(binding, {
924
948
  boundRoot: observed,
925
949
  claimedRoot: null,
926
950
  updatedAt: new Date().toISOString(),