@codyswann/lisa 3.33.4 → 3.33.6

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 (108) hide show
  1. package/all/copy-overwrite/scripts/check-state-classification.mjs +18 -4
  2. package/all/copy-overwrite/scripts/lisa-gates.mjs +47 -46
  3. package/all/copy-overwrite/scripts/lisa-run-gates.mjs +3 -2
  4. package/dist/configs/eslint/base.d.ts +21 -0
  5. package/dist/configs/eslint/base.d.ts.map +1 -1
  6. package/dist/configs/eslint/base.js +78 -2
  7. package/dist/configs/eslint/base.js.map +1 -1
  8. package/dist/configs/eslint/cdk.d.ts.map +1 -1
  9. package/dist/configs/eslint/cdk.js +5 -1
  10. package/dist/configs/eslint/cdk.js.map +1 -1
  11. package/dist/configs/eslint/expo.d.ts.map +1 -1
  12. package/dist/configs/eslint/expo.js +5 -1
  13. package/dist/configs/eslint/expo.js.map +1 -1
  14. package/dist/configs/eslint/harper-fabric.d.ts.map +1 -1
  15. package/dist/configs/eslint/harper-fabric.js +6 -1
  16. package/dist/configs/eslint/harper-fabric.js.map +1 -1
  17. package/dist/configs/eslint/nestjs.d.ts.map +1 -1
  18. package/dist/configs/eslint/nestjs.js +5 -1
  19. package/dist/configs/eslint/nestjs.js.map +1 -1
  20. package/dist/configs/eslint/phaser.d.ts.map +1 -1
  21. package/dist/configs/eslint/phaser.js +6 -1
  22. package/dist/configs/eslint/phaser.js.map +1 -1
  23. package/dist/configs/eslint/typescript.d.ts +2 -2
  24. package/dist/configs/eslint/typescript.d.ts.map +1 -1
  25. package/dist/configs/eslint/typescript.js +6 -2
  26. package/dist/configs/eslint/typescript.js.map +1 -1
  27. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  28. package/dist/core/lisa-owned-hash-ledger.js +11 -0
  29. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  30. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  31. package/dist/core/upstream-evidence-manifest.js +29 -28
  32. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  33. package/expo/copy-overwrite/scripts/bdd/baseline.mjs +11 -4
  34. package/expo/copy-overwrite/scripts/bdd/discover.mjs +12 -6
  35. package/expo/copy-overwrite/scripts/bdd/waivers.mjs +7 -4
  36. package/expo/copy-overwrite/scripts/bdd-matrix.mjs +1 -0
  37. package/expo/copy-overwrite/scripts/check-bdd-coverage.mjs +26 -17
  38. package/expo/copy-overwrite/scripts/check-e2e-coverage.mjs +12 -8
  39. package/package.json +1 -1
  40. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa-agy/plugin.json +1 -1
  43. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  45. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  46. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  52. package/plugins/lisa-expo-agy/plugin.json +1 -1
  53. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  58. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  63. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  68. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  72. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  73. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  77. package/plugins/lisa-rails-agy/plugin.json +1 -1
  78. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  82. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  83. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  87. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  88. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  90. package/scripts/check-conflict-markers.mjs +1 -1
  91. package/scripts/check-required-check-promotions.mjs +8 -4
  92. package/scripts/detect-stale-workflow-inputs.mjs +1 -3
  93. package/scripts/fix-namespace-test-assertions.mjs +1 -1
  94. package/scripts/generate-agy-plugin-artifacts.mjs +12 -7
  95. package/scripts/generate-codex-plugin-artifacts.mjs +14 -9
  96. package/scripts/generate-copilot-plugin-artifacts.mjs +1 -1
  97. package/scripts/generate-cursor-plugin-artifacts.mjs +2 -2
  98. package/scripts/generate-upstream-evidence-manifest.mjs +1 -1
  99. package/scripts/lisa-assert-eas-profile.mjs +3 -3
  100. package/scripts/plugin-parity-drift.mjs +29 -13
  101. package/scripts/plugin-routing-validate.mjs +8 -2
  102. package/scripts/update-node-version.ts +7 -3
  103. package/scripts/verify-health-agentic-built.mjs +27 -20
  104. package/scripts/verify-health-consumer-built.mjs +7 -3
  105. package/scripts/verify-health-deterministic-built.mjs +24 -19
  106. package/typescript/copy-overwrite/eslint.ignore.config.json +0 -2
  107. package/typescript/copy-overwrite/scripts/check-nightly-e2e-health.mjs +9 -4
  108. package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +1 -3
@@ -38,6 +38,9 @@ import { parseFeatureSource, scenarioIdsIn } from "./parse.mjs";
38
38
 
39
39
  const defect = (code, message) => ({ code, message });
40
40
 
41
+ /** Defect / evidence code, named once. */
42
+ const SCENARIO_DELETED = "scenario-deleted";
43
+
41
44
  /** The maintainer-applied PR label that authorizes giving coverage back. */
42
45
  export const BASELINE_LABEL = "bdd-floor-baseline";
43
46
 
@@ -247,10 +250,14 @@ export function obligationKeys(scenarios, contract) {
247
250
 
248
251
  /**
249
252
  * Every `SCENARIO:platform` a waiver removes from the denominator.
253
+ *
254
+ * Exported because `bdd-matrix.mjs` calls it too. It was calling it WITHOUT an
255
+ * import — a live ReferenceError on every matrix render, invisible because this
256
+ * whole tree sat outside the ESLint config until #2658 put it back in.
250
257
  * @param {object|null} contract - A coverage map.
251
258
  * @returns {Set<string>} Waived keys.
252
259
  */
253
- function waivedKeys(contract) {
260
+ export function waivedKeys(contract) {
254
261
  return new Set(
255
262
  (contract?.platformWaivers ?? []).flatMap(waiver =>
256
263
  (waiver.platforms ?? []).map(platform => `${waiver.scenario}:${platform}`)
@@ -420,19 +427,19 @@ function deletionDefects(id, record, labels) {
420
427
  if (!record) {
421
428
  return [
422
429
  defect(
423
- "scenario-deleted",
430
+ SCENARIO_DELETED,
424
431
  `${id} was deleted from the contract. Retiring a behavior is @superseded, not deletion — deleting it shrinks the denominator instead of the gap. A genuine removal needs a retirements record and the "${BASELINE_LABEL}" label.`
425
432
  ),
426
433
  ];
427
434
  }
428
435
  const missing = RETIREMENT_FIELDS.filter(field => !record[field]);
429
436
  const defects = missing.map(field =>
430
- defect("scenario-deleted", `${id}: retirements record has no ${field}`)
437
+ defect(SCENARIO_DELETED, `${id}: retirements record has no ${field}`)
431
438
  );
432
439
  if (!labels.includes(BASELINE_LABEL)) {
433
440
  defects.push(
434
441
  defect(
435
- "scenario-deleted",
442
+ SCENARIO_DELETED,
436
443
  `${id}: a retirement needs the maintainer-applied "${BASELINE_LABEL}" label`
437
444
  )
438
445
  );
@@ -69,6 +69,12 @@ export function isUnderPrefix(relative, prefix) {
69
69
  */
70
70
  const defect = (code, message, subject) => ({ code, message, subject });
71
71
 
72
+ /** Defect / evidence code, named once. */
73
+ const CALL_TITLE = "call-title";
74
+
75
+ /** Defect / evidence code, named once. */
76
+ const EXCLUSION_STALE = "exclusion-stale";
77
+
72
78
  /**
73
79
  * The evidence grammars a project may choose from, as SOURCE CONSTANTS.
74
80
  *
@@ -78,7 +84,7 @@ const defect = (code, message, subject) => ({ code, message, subject });
78
84
  * (`test("...")`, `it.skip('...')`); `line-field` reads a leading document
79
85
  * field (`name: ...`), which is how flow-style runners title a file.
80
86
  */
81
- export const EVIDENCE_KINDS = Object.freeze(["call-title", "line-field"]);
87
+ export const EVIDENCE_KINDS = Object.freeze([CALL_TITLE, "line-field"]);
82
88
 
83
89
  /** A JavaScript identifier, the only shape a declared function name may take. */
84
90
  const IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
@@ -176,7 +182,7 @@ function evidenceProblems(evidence) {
176
182
  `evidence.kind ${JSON.stringify(evidence.kind)} is not one of ${EVIDENCE_KINDS.join(", ")}`,
177
183
  ];
178
184
  }
179
- if (evidence.kind === "call-title") {
185
+ if (evidence.kind === CALL_TITLE) {
180
186
  return isListOf(
181
187
  evidence.functions,
182
188
  entry => typeof entry === "string" && IDENTIFIER.test(entry)
@@ -316,7 +322,7 @@ function discoverRunner({ root, runner, config, contract }) {
316
322
  * @returns {{evidence: string|null, dynamic: boolean}[]} Discovered entries.
317
323
  */
318
324
  function extract(source, evidence) {
319
- return evidence.kind === "call-title"
325
+ return evidence.kind === CALL_TITLE
320
326
  ? callTitles(source, evidence.functions)
321
327
  : lineField(source, evidence.field);
322
328
  }
@@ -485,7 +491,7 @@ function exclusionStale({ root, exclusion, discovery, at, subject }) {
485
491
  if (!resolved.path) {
486
492
  return [
487
493
  defect(
488
- "exclusion-stale",
494
+ EXCLUSION_STALE,
489
495
  `${at}: ${exclusion.file} — ${resolved.error}; retire the exclusion or restore the file`,
490
496
  subject
491
497
  ),
@@ -494,7 +500,7 @@ function exclusionStale({ root, exclusion, discovery, at, subject }) {
494
500
  if (!discovery.roots.some(entry => isUnderPrefix(exclusion.file, entry))) {
495
501
  return [
496
502
  defect(
497
- "exclusion-stale",
503
+ EXCLUSION_STALE,
498
504
  `${at}: ${exclusion.file} is covered by no configured discovery root (${discovery.roots.map(entry => entry || ".").join(", ") || "none declared"}), so the exclusion suppresses nothing`,
499
505
  subject
500
506
  ),
@@ -504,7 +510,7 @@ function exclusionStale({ root, exclusion, discovery, at, subject }) {
504
510
  ? []
505
511
  : [
506
512
  defect(
507
- "exclusion-stale",
513
+ EXCLUSION_STALE,
508
514
  `${at}: no discovered test in ${exclusion.file} matches ${JSON.stringify(exclusion.evidence)}`,
509
515
  subject
510
516
  ),
@@ -24,6 +24,9 @@ const REQUIRED_FIELDS = [
24
24
  "expiresAt",
25
25
  ];
26
26
 
27
+ /** Defect / evidence code, named once. */
28
+ const WAIVER_METADATA = "waiver-metadata";
29
+
27
30
  /** ISO calendar date, the only accepted date shape. */
28
31
  export const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
29
32
 
@@ -48,7 +51,7 @@ export function validateWaivers({ scenarios, contract, today }) {
48
51
  ? []
49
52
  : [
50
53
  defect(
51
- "waiver-metadata",
54
+ WAIVER_METADATA,
52
55
  `the evaluation date ${JSON.stringify(today ?? null)} is not an ISO date (YYYY-MM-DD), so no waiver expiry could be evaluated. Set BDD_TODAY to a calendar date or leave it unset.`
53
56
  ),
54
57
  ];
@@ -118,13 +121,13 @@ function blockingError(waiver, scenario, at) {
118
121
  */
119
122
  function metadataDefects(waiver, at, today) {
120
123
  const defects = REQUIRED_FIELDS.filter(field => !waiver[field]).map(field =>
121
- defect("waiver-metadata", `${at}: has no ${field}`)
124
+ defect(WAIVER_METADATA, `${at}: has no ${field}`)
122
125
  );
123
126
  for (const field of ["recordedAt", "expiresAt"]) {
124
127
  if (waiver[field] && !ISO_DATE.test(waiver[field])) {
125
128
  defects.push(
126
129
  defect(
127
- "waiver-metadata",
130
+ WAIVER_METADATA,
128
131
  `${at}: ${field} must be an ISO date (YYYY-MM-DD)`
129
132
  )
130
133
  );
@@ -136,7 +139,7 @@ function metadataDefects(waiver, at, today) {
136
139
  ) {
137
140
  defects.push(
138
141
  defect(
139
- "waiver-metadata",
142
+ WAIVER_METADATA,
140
143
  `${at}: ticket ${waiver.ticket} is not a valid tracker reference`
141
144
  )
142
145
  );
@@ -23,6 +23,7 @@ import * as fs from "node:fs";
23
23
  import * as path from "node:path";
24
24
  import { fileURLToPath } from "node:url";
25
25
 
26
+ import { waivedKeys } from "./bdd/baseline.mjs";
26
27
  import { byCodeUnit, declaredPlatforms, trackerUrl } from "./bdd/contract.mjs";
27
28
  import { loadScenarios } from "./bdd/parse.mjs";
28
29
  import { indexResults } from "./bdd/report.mjs";
@@ -90,6 +90,18 @@ const PACKAGE_ROOT = path.resolve(
90
90
  const MAP_REL = "bdd/coverage-map.json";
91
91
  const defect = (code, message) => ({ code, message });
92
92
 
93
+ /** Defect / mode code, named once. */
94
+ const NOT_ADOPTED = "not-adopted";
95
+
96
+ /** Defect / mode code, named once. */
97
+ const BOOTSTRAP_METADATA = "bootstrap-metadata";
98
+
99
+ /** Defect / mode code, named once. */
100
+ const EXECUTION_RESULTS = "execution-results";
101
+
102
+ /** Defect / mode code, named once. */
103
+ const EMPTY_CONTRACT = "empty-contract";
104
+
93
105
  /**
94
106
  * Resolve the adoption state from the environment.
95
107
  * @param {Record<string, string|undefined>} env - Process environment.
@@ -97,10 +109,10 @@ const defect = (code, message) => ({ code, message });
97
109
  */
98
110
  export function resolveMode(env) {
99
111
  const raw = (env.BDD_MODE ?? "").trim();
100
- if (raw === "") return { mode: "not-adopted", error: null };
112
+ if (raw === "") return { mode: NOT_ADOPTED, error: null };
101
113
  if (!ADOPTION_STATES.includes(raw)) {
102
114
  return {
103
- mode: "not-adopted",
115
+ mode: NOT_ADOPTED,
104
116
  error: `BDD_MODE="${raw}" is not one of ${ADOPTION_STATES.join(", ")}`,
105
117
  };
106
118
  }
@@ -188,7 +200,7 @@ function bootstrapDefects(adoption, today) {
188
200
  // would make the time-box unreachable and bootstrap permanent.
189
201
  defects.push(
190
202
  defect(
191
- "bootstrap-metadata",
203
+ BOOTSTRAP_METADATA,
192
204
  `the evaluation date ${JSON.stringify(today ?? null)} is not an ISO date (YYYY-MM-DD), so the bootstrap expiry could not be evaluated`
193
205
  )
194
206
  );
@@ -196,7 +208,7 @@ function bootstrapDefects(adoption, today) {
196
208
  if (!adoption.owner) {
197
209
  defects.push(
198
210
  defect(
199
- "bootstrap-metadata",
211
+ BOOTSTRAP_METADATA,
200
212
  "bootstrap requires adoption.owner (a named person, not a team)"
201
213
  )
202
214
  );
@@ -204,14 +216,14 @@ function bootstrapDefects(adoption, today) {
204
216
  if (!adoption.expiresAt) {
205
217
  defects.push(
206
218
  defect(
207
- "bootstrap-metadata",
219
+ BOOTSTRAP_METADATA,
208
220
  "bootstrap requires adoption.expiresAt (an ISO date); a bootstrap with no time-box never ends"
209
221
  )
210
222
  );
211
223
  } else if (!ISO_DATE.test(adoption.expiresAt)) {
212
224
  defects.push(
213
225
  defect(
214
- "bootstrap-metadata",
226
+ BOOTSTRAP_METADATA,
215
227
  "adoption.expiresAt must be an ISO date (YYYY-MM-DD)"
216
228
  )
217
229
  );
@@ -239,7 +251,7 @@ export function loadExecutionResults(root, files) {
239
251
  const resolved = path.resolve(root, file);
240
252
  if (!fs.existsSync(resolved)) {
241
253
  defects.push(
242
- defect("execution-results", `execution results not found: ${file}`)
254
+ defect(EXECUTION_RESULTS, `execution results not found: ${file}`)
243
255
  );
244
256
  continue;
245
257
  }
@@ -248,17 +260,14 @@ export function loadExecutionResults(root, files) {
248
260
  for (const run of Array.isArray(parsed) ? parsed : [parsed]) {
249
261
  if (!run.runner) {
250
262
  defects.push(
251
- defect(
252
- "execution-results",
253
- `${file}: each run must name its runner`
254
- )
263
+ defect(EXECUTION_RESULTS, `${file}: each run must name its runner`)
255
264
  );
256
265
  continue;
257
266
  }
258
267
  runs.push(run);
259
268
  }
260
269
  } catch (error) {
261
- defects.push(defect("execution-results", `${file}: ${error.message}`));
270
+ defects.push(defect(EXECUTION_RESULTS, `${file}: ${error.message}`));
262
271
  }
263
272
  }
264
273
  return { runs, defects };
@@ -372,7 +381,7 @@ function enforcedDefects({ contract, scenarios, report, discovery }) {
372
381
  if (scenarios.length === 0) {
373
382
  defects.push(
374
383
  defect(
375
- "empty-contract",
384
+ EMPTY_CONTRACT,
376
385
  "enforced mode: bdd/features declares zero scenarios"
377
386
  )
378
387
  );
@@ -380,7 +389,7 @@ function enforcedDefects({ contract, scenarios, report, discovery }) {
380
389
  if ((contract.mappings ?? []).length === 0) {
381
390
  defects.push(
382
391
  defect(
383
- "empty-contract",
392
+ EMPTY_CONTRACT,
384
393
  "enforced mode: bdd/coverage-map.json declares zero test mappings"
385
394
  )
386
395
  );
@@ -388,7 +397,7 @@ function enforcedDefects({ contract, scenarios, report, discovery }) {
388
397
  if (Object.keys(contract.runnerPlatforms ?? {}).length === 0) {
389
398
  defects.push(
390
399
  defect(
391
- "empty-contract",
400
+ EMPTY_CONTRACT,
392
401
  "enforced mode: bdd/coverage-map.json declares no runnerPlatforms"
393
402
  )
394
403
  );
@@ -494,7 +503,7 @@ export function run(root, options) {
494
503
  */
495
504
  function configFatals(loaded, mode) {
496
505
  if (loaded.error) return defect("config-malformed", loaded.error);
497
- if (loaded.present || mode === "not-adopted") return null;
506
+ if (loaded.present || mode === NOT_ADOPTED) return null;
498
507
  return defect(
499
508
  "config-absent",
500
509
  `${mode} mode requires ${MAP_REL}, which does not exist. In ${mode} mode absence is a failure, never a skip.`
@@ -562,7 +571,7 @@ function result({ mode, defects, report, contract }) {
562
571
  function statusFor({ mode, defects, fatal, report }) {
563
572
  if (defects.some(item => INVALID_CODES.includes(item.code))) return "invalid";
564
573
  if (fatal) return "failed";
565
- if (mode === "not-adopted" && !report) return "not-adopted";
574
+ if (mode === NOT_ADOPTED && !report) return NOT_ADOPTED;
566
575
  return "completed";
567
576
  }
568
577
 
@@ -596,21 +596,24 @@ function main() {
596
596
  ]) {
597
597
  if (collected.skipped.length > 0) {
598
598
  console.log(
599
- `[e2e-coverage] ${runner}: ${collected.skipped.length} file(s) excluded from the run and NOT counted as coverage:\n` +
600
- collected.skipped.map(file => ` - ${file}`).join("\n")
599
+ `[e2e-coverage] ${runner}: ${collected.skipped.length} file(s) excluded from the run and NOT counted as coverage:\n${collected.skipped
600
+ .map(file => ` - ${file}`)
601
+ .join("\n")}`
601
602
  );
602
603
  }
603
604
  }
604
605
  if (exempt.length > 0) {
605
606
  console.log(
606
- `[e2e-coverage] ${exempt.length} route(s) deliberately exempt (removed from the denominator):\n` +
607
- exempt.map(route => ` - ${route}`).join("\n")
607
+ `[e2e-coverage] ${exempt.length} route(s) deliberately exempt (removed from the denominator):\n${exempt
608
+ .map(route => ` - ${route}`)
609
+ .join("\n")}`
608
610
  );
609
611
  }
610
612
  if (unknown.length > 0) {
611
613
  console.error(
612
- `[e2e-coverage] FAIL: ${unknown.length} exemption(s) name a route that does not exist. A waiver that outlived its screen permanently excuses whatever replaces it:\n` +
613
- unknown.map(route => ` - ${route}`).join("\n")
614
+ `[e2e-coverage] FAIL: ${unknown.length} exemption(s) name a route that does not exist. A waiver that outlived its screen permanently excuses whatever replaces it:\n${unknown
615
+ .map(route => ` - ${route}`)
616
+ .join("\n")}`
614
617
  );
615
618
  process.exit(1);
616
619
  return;
@@ -641,8 +644,9 @@ function main() {
641
644
  } else {
642
645
  console.error(`[e2e-coverage] ${runner}: FAIL — ${summary}`);
643
646
  console.error(
644
- `[e2e-coverage] ${runner}: screens with no e2e test yet:\n` +
645
- verdict.missing.map(route => ` - ${route}`).join("\n")
647
+ `[e2e-coverage] ${runner}: screens with no e2e test yet:\n${verdict.missing
648
+ .map(route => ` - ${route}`)
649
+ .join("\n")}`
646
650
  );
647
651
  }
648
652
  }
package/package.json CHANGED
@@ -131,7 +131,7 @@
131
131
  "ws": ">=8.21.0"
132
132
  },
133
133
  "name": "@codyswann/lisa",
134
- "version": "3.33.4",
134
+ "version": "3.33.6",
135
135
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
136
136
  "main": "dist/index.js",
137
137
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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-expo",
3
- "version": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
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": "3.33.4",
3
+ "version": "3.33.6",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"