@codyswann/lisa 4.66.2 → 4.66.3

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 (68) hide show
  1. package/all/copy-overwrite/scripts/lisa-hooks/worktree-binding-guard.mjs +128 -50
  2. package/cdk/create-only/.github/workflows/deploy.yml +10 -0
  3. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  4. package/dist/core/lisa-owned-hash-ledger.js +6 -0
  5. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  6. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  7. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  8. package/dist/core/upstream-evidence-manifest.js +7 -6
  9. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  10. package/dist/opencode/plugin-templates/lisa-block-direct-issue-create.ts +19 -4
  11. package/expo/create-only/.github/workflows/deploy.yml +10 -0
  12. package/nestjs/create-only/.github/workflows/deploy.yml +10 -0
  13. package/package.json +4 -4
  14. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  16. package/plugins/lisa/hooks/worktree-binding-guard.mjs +128 -50
  17. package/plugins/lisa-agy/plugin.json +1 -1
  18. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  20. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  21. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-copilot/hooks/worktree-binding-guard.mjs +128 -50
  25. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-cursor/hooks/worktree-binding-guard.mjs +128 -50
  27. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  29. package/plugins/lisa-expo-agy/plugin.json +1 -1
  30. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  40. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  45. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  50. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails-agy/plugin.json +1 -1
  55. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  60. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  65. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  67. package/plugins/src/base/hooks/worktree-binding-guard.mjs +128 -50
  68. package/typescript/copy-contents/.husky/commit-msg +31 -11
@@ -584,10 +584,12 @@ const LisaBlockDirectIssueCreate = async () => {
584
584
  /**
585
585
  * Tool names that are never a tracker creation, skipped before anything else.
586
586
  *
587
- * The canonical guard's own list, transcribed rather than adapted. It is a
588
- * cost gate, not a correctness gate — none of these names would survive the
589
- * verb and noun tests below anyway — so keeping it identical costs nothing
590
- * and removes one way for the two implementations to disagree.
587
+ * The canonical guard's own list, transcribed rather than adapted. It is
588
+ * mostly a cost gate, but not ONLY one: `TaskCreate` and friends satisfy
589
+ * both shape tests below, so for the `Task*` family this set is also the
590
+ * correctness decision — the canonical guard allows them unconditionally,
591
+ * and a port that skips them here rather than below is the only way to
592
+ * stay exactly as strict, never stricter.
591
593
  */
592
594
  const STRUCTURED_SKIP: ReadonlySet<string> = new Set([
593
595
  "Bash",
@@ -599,6 +601,19 @@ const LisaBlockDirectIssueCreate = async () => {
599
601
  "Grep",
600
602
  "Task",
601
603
  "TodoWrite",
604
+ // The `Task*` family is the runtime's in-session task list — LOCAL
605
+ // scratch, not a tracker write. `TaskCreate` satisfies both shape gates
606
+ // (create-verb + task noun) and carries `"type": "bug"` metadata the
607
+ // lisa-implement skill prescribes; absent from this set it is refused as
608
+ // a tracker creation here while the canonical guard allows it — making
609
+ // this port STRICTER, the one direction it is documented never to take
610
+ // (CodySwannGT/lisa#4274).
611
+ "TaskCreate",
612
+ "TaskGet",
613
+ "TaskList",
614
+ "TaskOutput",
615
+ "TaskStop",
616
+ "TaskUpdate",
602
617
  ]);
603
618
  /**
604
619
  * A creation verb in a tool name, matched on SHAPE rather than on a list of
@@ -154,6 +154,16 @@ jobs:
154
154
  SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
155
155
  SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
156
156
  SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
157
+ # Scanner tokens release.yml re-declares and forwards to quality.yml —
158
+ # without them the deploy-path quality run silently skips Sonar, Snyk,
159
+ # GitGuardian, FOSSA and Maestro (CodySwannGT/lisa#4287). Tracker
160
+ # credentials are deliberately absent: work_item_traceability is
161
+ # pull_request-only and never runs on the release path.
162
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
163
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
164
+ GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}
165
+ FOSSA_API_KEY: ${{ secrets.FOSSA_API_KEY }}
166
+ MAESTRO_API_KEY: ${{ secrets.MAESTRO_API_KEY }}
157
167
 
158
168
  # Step 2: Deploy to AWS (Custom deployment logic)
159
169
  check_eas_setup:
@@ -149,6 +149,16 @@ jobs:
149
149
  SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
150
150
  SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
151
151
  SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
152
+ # Scanner tokens release.yml re-declares and forwards to quality.yml —
153
+ # without them the deploy-path quality run silently skips Sonar, Snyk,
154
+ # GitGuardian, FOSSA and Maestro (CodySwannGT/lisa#4287). Tracker
155
+ # credentials are deliberately absent: work_item_traceability is
156
+ # pull_request-only and never runs on the release path.
157
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
158
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
159
+ GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}
160
+ FOSSA_API_KEY: ${{ secrets.FOSSA_API_KEY }}
161
+ MAESTRO_API_KEY: ${{ secrets.MAESTRO_API_KEY }}
152
162
 
153
163
  verify_aws_credentials:
154
164
  name: Verify AWS Credentials
package/package.json CHANGED
@@ -187,7 +187,7 @@
187
187
  "zod-validation-error": "^4.0.0"
188
188
  },
189
189
  "name": "@codyswann/lisa",
190
- "version": "4.66.2",
190
+ "version": "4.66.3",
191
191
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
192
192
  "main": "dist/index.js",
193
193
  "exports": {
@@ -336,7 +336,7 @@
336
336
  "test": "tests"
337
337
  },
338
338
  "types": "./dist/index.d.ts",
339
- "lisaReleaseCommit": "80f2ea7d119a11d3b2dc6497e20d10fb0c49b605",
340
- "gitHead": "80f2ea7d119a11d3b2dc6497e20d10fb0c49b605",
341
- "lisaReleaseTag": "v4.66.2"
339
+ "lisaReleaseCommit": "764ae79b79c134e967e35cfb75c0b7986f997216",
340
+ "gitHead": "764ae79b79c134e967e35cfb75c0b7986f997216",
341
+ "lisaReleaseTag": "v4.66.3"
342
342
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.66.2",
3
+ "version": "4.66.3",
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": "4.66.2",
3
+ "version": "4.66.3",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -511,6 +511,20 @@ function stateFile(bindingKey) {
511
511
  return join(home, "worktree-binding", `${bindingKey}.json`);
512
512
  }
513
513
 
514
+ /**
515
+ * Percent-escape every byte that is not filename-safe, so the output cannot
516
+ * contain `-` at all and two escaped parts can be joined on `--` without the
517
+ * joiner ever being smuggled in from either side.
518
+ *
519
+ * `:` and friends are folded too — the key lands in a filename and `:` is
520
+ * illegal on Windows/NTFS (CodySwannGT/lisa#4277).
521
+ * @param {string} value - One component of the binding key
522
+ * @returns {string} A component containing only `[A-Za-z0-9._]` and `%XX`
523
+ */
524
+ function keyPart(value) {
525
+ return encodeURIComponent(value).replaceAll("-", "%2D");
526
+ }
527
+
514
528
  /**
515
529
  * The identity a binding belongs to.
516
530
  *
@@ -524,22 +538,58 @@ function stateFile(bindingKey) {
524
538
  * session-scoped key it always had, which is also the fallback for runtimes
525
539
  * that never send the field.
526
540
  *
527
- * The key lands in a filename, so the composite is folded into a set that is
528
- * legal on every filesystem — `:` is not, which rules it out as a separator
529
- * and as tolerated session_id content on Windows hosts.
541
+ * Both shapes escape every component with {@link keyPart}, so the session key
542
+ * `x` and the agent key `a--b` live in disjoint namespaces: an escaped
543
+ * component never contains `-`, a main-session key is one component, an
544
+ * agent key is two joined by the only `--` the string can hold. Session
545
+ * "s%2Da--c" cannot collide with session "s-a" + agent "c", and neither can
546
+ * collide across the two shapes (CodySwannGT/lisa#4294).
530
547
  */
531
548
  function bindingKey(payload) {
532
549
  const agent = payload?.agent_id;
533
- if (typeof agent !== "string" || !agent) return payload.session_id;
534
- return `${payload.session_id}--${agent}`.replaceAll(/[^A-Za-z0-9._-]/g, "_");
550
+ if (typeof agent !== "string" || !agent) return keyPart(payload.session_id);
551
+ return `${keyPart(payload.session_id)}--${keyPart(agent)}`;
535
552
  }
536
553
 
537
- function readState(sessionId) {
538
- try {
539
- return JSON.parse(readFileSync(stateFile(sessionId), "utf8"));
540
- } catch {
541
- return null;
554
+ /**
555
+ * The keys earlier versions wrote for this payload, newest first.
556
+ *
557
+ * The v1 key was the raw `session_id` (single shared file per session). v2
558
+ * joined raw session and agent on `--`. Both are readable on upgrade so a
559
+ * mid-session deploy does not silently re-baseline an established binding —
560
+ * the ambiguity in a legacy `a--b` key is resolved toward the interpretation
561
+ * the lookup is making, and the next write lands on the current key while the
562
+ * legacy file is left to age out.
563
+ * @param {object} payload - The hook payload
564
+ * @returns {string[]} Zero or more legacy keys this payload may have written
565
+ */
566
+ function legacyKeys(payload) {
567
+ const agent = payload?.agent_id;
568
+ const session = payload.session_id;
569
+ if (typeof agent === "string" && agent) {
570
+ // v2 wrote the sanitised composite. v1 never wrote a per-agent file — an
571
+ // agent falling back to the shared session file is the #4277 bug again,
572
+ // so the list stops there.
573
+ const san = value => value.replaceAll(/[^A-Za-z0-9._-]/g, "_");
574
+ return [`${san(session)}--${san(agent)}`];
542
575
  }
576
+ // v1 and v2 both keyed the main agent on the raw session id — but only when
577
+ // that id contains no `--`. One that does spells exactly the composite
578
+ // shape agent bindings now write, so reading it could hand this session a
579
+ // stranger's binding. Losing the v1 binding for such an id re-baselines
580
+ // once; the alternative is reading a file whose owner cannot be proven.
581
+ return session.includes("--") ? [] : [session];
582
+ }
583
+
584
+ function readState(bindingKeyValue, payload) {
585
+ for (const key of [bindingKeyValue, ...legacyKeys(payload)]) {
586
+ try {
587
+ return JSON.parse(readFileSync(stateFile(key), "utf8"));
588
+ } catch {
589
+ // Not written under this key — try the next older one.
590
+ }
591
+ }
592
+ return null;
543
593
  }
544
594
 
545
595
  /**
@@ -552,17 +602,23 @@ function readState(sessionId) {
552
602
  * {@link noticeRuntimeDrift} and read by nobody else, and a clobbering write
553
603
  * would turn its "reported once" into "reported again after the next
554
604
  * acknowledgement", which is the noise the notice is designed not to be.
555
- * @param sessionId - The session whose state file this is
605
+ * @param bindingKeyValue - The key whose state file this is
556
606
  * @param state - Fields to write over the recorded state
607
+ * @param payload - The hook payload, for legacy-key reads while a binding is
608
+ * migrating to the current key format
557
609
  * @returns Whether the write succeeded
558
610
  */
559
- function writeState(sessionId, state) {
560
- const file = stateFile(sessionId);
611
+ function writeState(bindingKeyValue, state, payload) {
612
+ const file = stateFile(bindingKeyValue);
561
613
  try {
562
614
  mkdirSync(dirname(file), { recursive: true });
563
615
  writeFileSync(
564
616
  file,
565
- `${JSON.stringify({ ...readState(sessionId), ...state }, null, 2)}\n`
617
+ `${JSON.stringify(
618
+ { ...readState(bindingKeyValue, payload), ...state },
619
+ null,
620
+ 2
621
+ )}\n`
566
622
  );
567
623
  return true;
568
624
  } catch (error) {
@@ -637,19 +693,24 @@ function claimedRoot(toolInput, cwd) {
637
693
  *
638
694
  * Returns nothing on purpose, like its sibling below: SessionStart has no call
639
695
  * to refuse, so every path through it allows.
640
- * @param sessionId - The session this baseline belongs to
696
+ * @param bindingKeyValue - The key this baseline belongs to
641
697
  * @param observed - The worktree root the session started in
698
+ * @param payload - The hook payload, for legacy-key reads
642
699
  */
643
- function recordBaseline(sessionId, observed) {
700
+ function recordBaseline(bindingKeyValue, observed, payload) {
644
701
  // Never overwrite. A resumed session, a reconnect, or anything else that
645
702
  // fires the event twice must not be able to launder a displaced binding into
646
703
  // a fresh baseline — which is the whole failure this exists to close.
647
- if (readState(sessionId)?.boundRoot) return;
648
- writeState(sessionId, {
649
- boundRoot: observed,
650
- claimedRoot: null,
651
- updatedAt: new Date().toISOString(),
652
- });
704
+ if (readState(bindingKeyValue, payload)?.boundRoot) return;
705
+ writeState(
706
+ bindingKeyValue,
707
+ {
708
+ boundRoot: observed,
709
+ claimedRoot: null,
710
+ updatedAt: new Date().toISOString(),
711
+ },
712
+ payload
713
+ );
653
714
  }
654
715
 
655
716
  /**
@@ -663,12 +724,16 @@ function recordBaseline(sessionId, observed) {
663
724
  function recordClaim(payload, observed) {
664
725
  const claimed = claimedRoot(payload.tool_input, payload.cwd);
665
726
  if (!claimed || claimed === observed) return;
666
- const previous = readState(bindingKey(payload));
667
- writeState(bindingKey(payload), {
668
- boundRoot: previous?.boundRoot ?? observed,
669
- claimedRoot: claimed,
670
- updatedAt: new Date().toISOString(),
671
- });
727
+ const previous = readState(bindingKey(payload), payload);
728
+ writeState(
729
+ bindingKey(payload),
730
+ {
731
+ boundRoot: previous?.boundRoot ?? observed,
732
+ claimedRoot: claimed,
733
+ updatedAt: new Date().toISOString(),
734
+ },
735
+ payload
736
+ );
672
737
  }
673
738
 
674
739
  function refuse(lines) {
@@ -704,11 +769,15 @@ function handleAcceptance(payload, observed) {
704
769
  acceptanceLine(observed),
705
770
  ]);
706
771
  }
707
- writeState(bindingKey(payload), {
708
- boundRoot: observed,
709
- claimedRoot: null,
710
- updatedAt: new Date().toISOString(),
711
- });
772
+ writeState(
773
+ bindingKey(payload),
774
+ {
775
+ boundRoot: observed,
776
+ claimedRoot: null,
777
+ updatedAt: new Date().toISOString(),
778
+ },
779
+ payload
780
+ );
712
781
  say(`bound to ${observed}`);
713
782
  return 0;
714
783
  }
@@ -880,15 +949,16 @@ function driftNotice(version) {
880
949
  * Never refuses. The dependency is a reporting gap, not a live displacement,
881
950
  * and blocking a session over a version number would be a wall where an
882
951
  * observation belongs.
883
- * @param sessionId - The session being started
952
+ * @param bindingKeyValue - The key being started
884
953
  * @param env - Environment to read the runtime version from
954
+ * @param payload - The hook payload, for legacy-key reads
885
955
  * @returns Nothing; every path through this allows
886
956
  */
887
- function noticeRuntimeDrift(sessionId, env) {
957
+ function noticeRuntimeDrift(bindingKeyValue, env, payload) {
888
958
  const version = runtimeVersion(env);
889
959
  if (version === null || version === VERIFIED_RUNTIME_VERSION) return;
890
- if (readState(sessionId)?.runtimeNoticed === version) return;
891
- writeState(sessionId, { runtimeNoticed: version });
960
+ if (readState(bindingKeyValue, payload)?.runtimeNoticed === version) return;
961
+ writeState(bindingKeyValue, { runtimeNoticed: version }, payload);
892
962
  process.stdout.write(
893
963
  `${JSON.stringify({
894
964
  hookSpecificOutput: {
@@ -911,11 +981,11 @@ function evaluate(payload) {
911
981
  if (!observed) return 0;
912
982
 
913
983
  if (payload.hook_event_name === "SessionStart") {
914
- recordBaseline(binding, observed);
984
+ recordBaseline(binding, observed, payload);
915
985
  // After the baseline, never before: `recordBaseline` writes a fresh state
916
986
  // for a session it has not seen, and the notice's record has to go on top
917
987
  // of that write rather than under it.
918
- noticeRuntimeDrift(binding, process.env);
988
+ noticeRuntimeDrift(binding, process.env, payload);
919
989
  return 0;
920
990
  }
921
991
  if (payload.tool_name === "EnterWorktree") {
@@ -927,7 +997,7 @@ function evaluate(payload) {
927
997
  const accepted = handleAcceptance(payload, observed);
928
998
  if (accepted !== null) return accepted;
929
999
 
930
- const state = readState(binding);
1000
+ const state = readState(binding, payload);
931
1001
  if (!state?.boundRoot) {
932
1002
  // No baseline means SessionStart did not run for this session — an older
933
1003
  // install, a runtime that fires no such event, a harness that skips it.
@@ -936,22 +1006,30 @@ function evaluate(payload) {
936
1006
  // refusing. Treating it as a refusal would turn a floor into a wall on
937
1007
  // every surface where the event does not fire, and a wall gets switched
938
1008
  // off, which costs the whole guard.
939
- writeState(binding, {
940
- boundRoot: observed,
941
- claimedRoot: null,
942
- updatedAt: new Date().toISOString(),
943
- });
1009
+ writeState(
1010
+ binding,
1011
+ {
1012
+ boundRoot: observed,
1013
+ claimedRoot: null,
1014
+ updatedAt: new Date().toISOString(),
1015
+ },
1016
+ payload
1017
+ );
944
1018
  return 0;
945
1019
  }
946
1020
  if (state.claimedRoot && state.claimedRoot !== observed) {
947
1021
  return unconfirmedSwitch(state.claimedRoot, observed);
948
1022
  }
949
1023
  if (state.claimedRoot === observed) {
950
- writeState(binding, {
951
- boundRoot: observed,
952
- claimedRoot: null,
953
- updatedAt: new Date().toISOString(),
954
- });
1024
+ writeState(
1025
+ binding,
1026
+ {
1027
+ boundRoot: observed,
1028
+ claimedRoot: null,
1029
+ updatedAt: new Date().toISOString(),
1030
+ },
1031
+ payload
1032
+ );
955
1033
  return 0;
956
1034
  }
957
1035
  if (state.boundRoot !== observed) return displaced(state.boundRoot, observed);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.66.2",
3
+ "version": "4.66.3",
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-cdk",
3
- "version": "4.66.2",
3
+ "version": "4.66.3",
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": "4.66.2",
3
+ "version": "4.66.3",
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": "4.66.2",
3
+ "version": "4.66.3",
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": "4.66.2",
3
+ "version": "4.66.3",
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": "4.66.2",
3
+ "version": "4.66.3",
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": "4.66.2",
3
+ "version": "4.66.3",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"