@codyswann/lisa 2.333.2 → 2.334.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 (66) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +4 -2
  3. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  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-drive-pr-to-merge/SKILL.md +12 -3
  8. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +113 -3
  9. package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +12 -3
  10. package/plugins/lisa/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +113 -3
  11. package/plugins/lisa-agy/plugin.json +1 -1
  12. package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +12 -3
  13. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +113 -3
  14. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  16. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  17. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +12 -3
  21. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +113 -3
  22. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +12 -3
  24. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +113 -3
  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/skills/lisa-drive-pr-to-merge/SKILL.md +12 -3
  66. package/plugins/src/base/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +113 -3
@@ -191,6 +191,38 @@ export function installProfileSourcing(valuesFile, options = {}) {
191
191
  * @param {object} [options] Home directory and file seams, for tests.
192
192
  * @returns {string[]} The profile names written.
193
193
  */
194
+ /**
195
+ * Profile names already defined OUTSIDE this module's managed block.
196
+ *
197
+ * Only what lies outside the block counts: our own previous output is meant to
198
+ * be replaced, and treating it as a collision would make the second run fail.
199
+ * @param {string} dir The `.aws` directory.
200
+ * @param {string[]} names Profile names about to be written.
201
+ * @param {object} io `exists` and `read` seams.
202
+ * @returns {string[]} Colliding names, in the order given.
203
+ */
204
+ export function collidingProfiles(dir, names, io = {}) {
205
+ const { exists = existsSync, read = readFileSync } = io;
206
+ const file = join(dir, "config");
207
+ if (!exists(file)) return [];
208
+
209
+ const text = String(read(file, "utf8"));
210
+ const start = text.indexOf(MANAGED_MARKER);
211
+ const endAt = start === -1 ? -1 : text.indexOf(MANAGED_END, start);
212
+ const outside =
213
+ start === -1
214
+ ? text
215
+ : text.slice(0, start) +
216
+ (endAt === -1 ? "" : text.slice(endAt + MANAGED_END.length));
217
+
218
+ return names.filter(name =>
219
+ new RegExp(
220
+ `^\\s*\\[profile\\s+${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*\\]`,
221
+ "m"
222
+ ).test(outside)
223
+ );
224
+ }
225
+
194
226
  export function installAwsProfiles(bundle, options = {}) {
195
227
  const {
196
228
  home = process.env.HOME || homedir(),
@@ -205,6 +237,33 @@ export function installAwsProfiles(bundle, options = {}) {
205
237
  if (!rendered) return [];
206
238
 
207
239
  const dir = join(home, ".aws");
240
+
241
+ // Refuse to write a profile name the operator already uses outside our block.
242
+ //
243
+ // AWS does not error on a duplicate `[profile x]` — it resolves one and
244
+ // ignores the other. So writing `tunnl-dev` next to an operator's existing SSO
245
+ // `tunnl-dev` would silently run some calls as the wrong identity, which is
246
+ // worse than either winning outright. Merging protects their sections from
247
+ // being deleted; this protects them from being shadowed.
248
+ //
249
+ // Deliberately not resolved by renaming theirs: this module writes its own
250
+ // block and nothing else. The operator renames (conventionally to `-sso`) and
251
+ // re-runs.
252
+ const collisions = collidingProfiles(dir, rendered.profiles, {
253
+ exists,
254
+ read,
255
+ });
256
+ if (collisions.length > 0) {
257
+ throw new Error(
258
+ `~/.aws/config already defines ${collisions.map(n => `"${n}"`).join(", ")} ` +
259
+ `outside the lisa-managed block.\n` +
260
+ `Writing them would create duplicate sections, and AWS resolves only ` +
261
+ `one — some calls would silently use the wrong identity.\n` +
262
+ `Rename the existing entries (for example to "${collisions[0]}-sso") ` +
263
+ `and run this again.`
264
+ );
265
+ }
266
+
208
267
  mkdir(dir, { recursive: true, mode: 0o700 });
209
268
  chmod(dir, 0o700);
210
269
 
@@ -297,6 +356,47 @@ export function materialize(cfg = readConfig()) {
297
356
 
298
357
  function main() {
299
358
  const cfg = readConfig();
359
+
360
+ // `--aws-profiles-only` writes ~/.aws and NOTHING else, on any surface.
361
+ //
362
+ // A laptop refuses to materialize secrets to disk, deliberately: read-through
363
+ // to the provider adds no drift and leaves no copy. That rule is about the
364
+ // thirteen values in secrets.env, and it stays exactly as it was here.
365
+ //
366
+ // The AWS profiles are a different bargain, requested explicitly. Agents
367
+ // working on a developer's machine should act as RemoteAgent rather than
368
+ // borrowing the human's SSO identity — separate attribution in CloudTrail,
369
+ // the role's blast radius instead of a person's, and the same `agent-*`
370
+ // profile names as a container so a script does not need two vocabularies.
371
+ //
372
+ // The cost is real and belongs in the open: `source_profile` needs a
373
+ // long-lived key pair, so this writes one to a machine that is not
374
+ // disposable, which is the thing the local surface otherwise prevents. It is
375
+ // therefore opt-in per run, never automatic, and never part of a normal
376
+ // materialize.
377
+ if (process.argv.includes("--aws-profiles-only")) {
378
+ const selected = fetchAll(cfg);
379
+ const bundle = parseBootstrap(selected.get(BOOTSTRAP_KEY)?.value);
380
+ const written = installAwsProfiles(bundle);
381
+
382
+ if (written.length === 0) {
383
+ console.log(
384
+ `no AWS profiles written — ${BOOTSTRAP_KEY} is absent, unparseable, ` +
385
+ `or declares no profile carrying a roleArn.`
386
+ );
387
+ return;
388
+ }
389
+ console.log(
390
+ `wrote ${written.length} AWS profile(s): ${written.join(", ")}`
391
+ );
392
+ console.log(
393
+ ` Sourced from a long-lived key pair in ~/.aws/credentials. Existing\n` +
394
+ ` sections were preserved — only the lisa-managed block was replaced.\n` +
395
+ ` Use them explicitly: aws --profile ${written[0]} ...`
396
+ );
397
+ return;
398
+ }
399
+
300
400
  if (process.argv.includes("--dry-run")) {
301
401
  const selected = fetchAll(cfg);
302
402
  // Derive here too, or the preview lies in the one place it matters most:
@@ -314,10 +414,20 @@ function main() {
314
414
  const { count, derived, dir } = materialize(cfg);
315
415
  console.log(`materialized ${count} secret(s) and their notes into ${dir}`);
316
416
  if (derived > 0) {
317
- // Said out loud: this run exported variables the host may also have set.
417
+ // Do not claim an override this does not perform.
418
+ //
419
+ // This line used to end "overriding any ambient value". That was true when
420
+ // the key pair was exported and stopped being true when the pair moved into
421
+ // ~/.aws and AWS_PROFILE took its place — AWS_PROFILE loses to ambient
422
+ // environment credentials, it does not beat them. The stale sentence sent
423
+ // two separate investigations after a credential problem that did not
424
+ // exist, while the real fault was that nothing sourced the file. A message
425
+ // that overclaims costs more than no message.
318
426
  console.log(
319
- ` ${derived} AWS variable(s) derived from the bootstrap bundle, ` +
320
- `overriding any ambient value`
427
+ ` ${derived} AWS variable(s) derived from the bootstrap bundle. ` +
428
+ `These take\n effect only in a shell that sourced the materialized ` +
429
+ `env file; ambient\n credentials outrank AWS_PROFILE, so prefer an ` +
430
+ `explicit --profile.`
321
431
  );
322
432
  }
323
433
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -14,9 +14,18 @@ merges" loop. Other skills delegate here instead of re-implementing it. Runs
14
14
 
15
15
  - `pr=<number|url>` — the PR to drive. Default: the PR for the current branch
16
16
  (`gh pr view --json number,url,baseRefName,headRefName,state`).
17
- - `merge_method=<merge|rebase>` — strategy for both auto-merge and the direct-merge
18
- fallback. Default `merge`. **Never squash** squashing flattens
19
- `chore(release): X.Y.Z [skip ci]` commits and breaks release promotion detection.
17
+ - `merge_method=<merge>` — strategy for both auto-merge and the direct-merge
18
+ fallback. Default and only accepted value: `merge`.
19
+ - **Never squash** — squashing flattens `chore(release): X.Y.Z [skip ci]`
20
+ commits and breaks release promotion detection.
21
+ - **Never rebase.** REJECT `merge_method=rebase` up front with a clear message
22
+ rather than accepting it and verifying it wrongly. GitHub's rebase-and-merge
23
+ rewrites the commits — new SHAs — and creates no merge commit, so the
24
+ shipped-verification in section 3 cannot succeed: `verify_commit` is the
25
+ pre-rebase SHA and is not an ancestor of the base branch afterwards, and the
26
+ merge-parent assertion has nothing to assert against. A successful merge
27
+ would then report as a FAILED verification and drive a false fix-forward,
28
+ which is worse than refusing the input. See CodySwannGT/lisa#2316.
20
29
  - `verify_commit=<sha>` — the commit that MUST end up in the merged base (for the
21
30
  ancestry check). Default: the PR head at the time this skill starts.
22
31
  - `auto_merge=<true|false>` — whether this skill is allowed to merge the PR at
@@ -191,6 +191,38 @@ export function installProfileSourcing(valuesFile, options = {}) {
191
191
  * @param {object} [options] Home directory and file seams, for tests.
192
192
  * @returns {string[]} The profile names written.
193
193
  */
194
+ /**
195
+ * Profile names already defined OUTSIDE this module's managed block.
196
+ *
197
+ * Only what lies outside the block counts: our own previous output is meant to
198
+ * be replaced, and treating it as a collision would make the second run fail.
199
+ * @param {string} dir The `.aws` directory.
200
+ * @param {string[]} names Profile names about to be written.
201
+ * @param {object} io `exists` and `read` seams.
202
+ * @returns {string[]} Colliding names, in the order given.
203
+ */
204
+ export function collidingProfiles(dir, names, io = {}) {
205
+ const { exists = existsSync, read = readFileSync } = io;
206
+ const file = join(dir, "config");
207
+ if (!exists(file)) return [];
208
+
209
+ const text = String(read(file, "utf8"));
210
+ const start = text.indexOf(MANAGED_MARKER);
211
+ const endAt = start === -1 ? -1 : text.indexOf(MANAGED_END, start);
212
+ const outside =
213
+ start === -1
214
+ ? text
215
+ : text.slice(0, start) +
216
+ (endAt === -1 ? "" : text.slice(endAt + MANAGED_END.length));
217
+
218
+ return names.filter(name =>
219
+ new RegExp(
220
+ `^\\s*\\[profile\\s+${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*\\]`,
221
+ "m"
222
+ ).test(outside)
223
+ );
224
+ }
225
+
194
226
  export function installAwsProfiles(bundle, options = {}) {
195
227
  const {
196
228
  home = process.env.HOME || homedir(),
@@ -205,6 +237,33 @@ export function installAwsProfiles(bundle, options = {}) {
205
237
  if (!rendered) return [];
206
238
 
207
239
  const dir = join(home, ".aws");
240
+
241
+ // Refuse to write a profile name the operator already uses outside our block.
242
+ //
243
+ // AWS does not error on a duplicate `[profile x]` — it resolves one and
244
+ // ignores the other. So writing `tunnl-dev` next to an operator's existing SSO
245
+ // `tunnl-dev` would silently run some calls as the wrong identity, which is
246
+ // worse than either winning outright. Merging protects their sections from
247
+ // being deleted; this protects them from being shadowed.
248
+ //
249
+ // Deliberately not resolved by renaming theirs: this module writes its own
250
+ // block and nothing else. The operator renames (conventionally to `-sso`) and
251
+ // re-runs.
252
+ const collisions = collidingProfiles(dir, rendered.profiles, {
253
+ exists,
254
+ read,
255
+ });
256
+ if (collisions.length > 0) {
257
+ throw new Error(
258
+ `~/.aws/config already defines ${collisions.map(n => `"${n}"`).join(", ")} ` +
259
+ `outside the lisa-managed block.\n` +
260
+ `Writing them would create duplicate sections, and AWS resolves only ` +
261
+ `one — some calls would silently use the wrong identity.\n` +
262
+ `Rename the existing entries (for example to "${collisions[0]}-sso") ` +
263
+ `and run this again.`
264
+ );
265
+ }
266
+
208
267
  mkdir(dir, { recursive: true, mode: 0o700 });
209
268
  chmod(dir, 0o700);
210
269
 
@@ -297,6 +356,47 @@ export function materialize(cfg = readConfig()) {
297
356
 
298
357
  function main() {
299
358
  const cfg = readConfig();
359
+
360
+ // `--aws-profiles-only` writes ~/.aws and NOTHING else, on any surface.
361
+ //
362
+ // A laptop refuses to materialize secrets to disk, deliberately: read-through
363
+ // to the provider adds no drift and leaves no copy. That rule is about the
364
+ // thirteen values in secrets.env, and it stays exactly as it was here.
365
+ //
366
+ // The AWS profiles are a different bargain, requested explicitly. Agents
367
+ // working on a developer's machine should act as RemoteAgent rather than
368
+ // borrowing the human's SSO identity — separate attribution in CloudTrail,
369
+ // the role's blast radius instead of a person's, and the same `agent-*`
370
+ // profile names as a container so a script does not need two vocabularies.
371
+ //
372
+ // The cost is real and belongs in the open: `source_profile` needs a
373
+ // long-lived key pair, so this writes one to a machine that is not
374
+ // disposable, which is the thing the local surface otherwise prevents. It is
375
+ // therefore opt-in per run, never automatic, and never part of a normal
376
+ // materialize.
377
+ if (process.argv.includes("--aws-profiles-only")) {
378
+ const selected = fetchAll(cfg);
379
+ const bundle = parseBootstrap(selected.get(BOOTSTRAP_KEY)?.value);
380
+ const written = installAwsProfiles(bundle);
381
+
382
+ if (written.length === 0) {
383
+ console.log(
384
+ `no AWS profiles written — ${BOOTSTRAP_KEY} is absent, unparseable, ` +
385
+ `or declares no profile carrying a roleArn.`
386
+ );
387
+ return;
388
+ }
389
+ console.log(
390
+ `wrote ${written.length} AWS profile(s): ${written.join(", ")}`
391
+ );
392
+ console.log(
393
+ ` Sourced from a long-lived key pair in ~/.aws/credentials. Existing\n` +
394
+ ` sections were preserved — only the lisa-managed block was replaced.\n` +
395
+ ` Use them explicitly: aws --profile ${written[0]} ...`
396
+ );
397
+ return;
398
+ }
399
+
300
400
  if (process.argv.includes("--dry-run")) {
301
401
  const selected = fetchAll(cfg);
302
402
  // Derive here too, or the preview lies in the one place it matters most:
@@ -314,10 +414,20 @@ function main() {
314
414
  const { count, derived, dir } = materialize(cfg);
315
415
  console.log(`materialized ${count} secret(s) and their notes into ${dir}`);
316
416
  if (derived > 0) {
317
- // Said out loud: this run exported variables the host may also have set.
417
+ // Do not claim an override this does not perform.
418
+ //
419
+ // This line used to end "overriding any ambient value". That was true when
420
+ // the key pair was exported and stopped being true when the pair moved into
421
+ // ~/.aws and AWS_PROFILE took its place — AWS_PROFILE loses to ambient
422
+ // environment credentials, it does not beat them. The stale sentence sent
423
+ // two separate investigations after a credential problem that did not
424
+ // exist, while the real fault was that nothing sourced the file. A message
425
+ // that overclaims costs more than no message.
318
426
  console.log(
319
- ` ${derived} AWS variable(s) derived from the bootstrap bundle, ` +
320
- `overriding any ambient value`
427
+ ` ${derived} AWS variable(s) derived from the bootstrap bundle. ` +
428
+ `These take\n effect only in a shell that sourced the materialized ` +
429
+ `env file; ambient\n credentials outrank AWS_PROFILE, so prefer an ` +
430
+ `explicit --profile.`
321
431
  );
322
432
  }
323
433
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.333.2",
3
+ "version": "2.334.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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": "2.333.2",
3
+ "version": "2.334.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"