@codyswann/lisa 4.56.2 → 4.56.4

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/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  2. package/dist/core/lisa-owned-hash-ledger.js +4 -0
  3. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  4. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  5. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  6. package/dist/core/upstream-evidence-manifest.js +5 -4
  7. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  8. package/package.json +4 -4
  9. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  10. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  11. package/plugins/lisa/hooks/threshold-ratchet-compare.mjs +42 -5
  12. package/plugins/lisa-agy/plugin.json +1 -1
  13. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  15. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  16. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-copilot/hooks/threshold-ratchet-compare.mjs +42 -5
  20. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-cursor/hooks/threshold-ratchet-compare.mjs +42 -5
  22. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  23. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  24. package/plugins/lisa-expo-agy/plugin.json +1 -1
  25. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  29. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  30. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  34. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  35. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  39. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  40. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  44. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  45. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  49. package/plugins/lisa-rails-agy/plugin.json +1 -1
  50. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  54. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  55. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  59. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  60. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  62. package/plugins/src/base/hooks/threshold-ratchet-compare.mjs +42 -5
  63. package/rails/copy-overwrite/scripts/threshold-ratchet-compare.mjs +42 -5
  64. package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +40 -12
  65. package/typescript/copy-overwrite/scripts/threshold-ratchet-compare.mjs +42 -5
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.56.2",
3
+ "version": "4.56.4",
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.56.2",
3
+ "version": "4.56.4",
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.56.2",
3
+ "version": "4.56.4",
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"
@@ -231,6 +231,47 @@ function compareAllowList(relPath, base, current) {
231
231
  return findings;
232
232
  }
233
233
 
234
+ /**
235
+ * Compare Lighthouse assertions, including the shipped detail checker's default.
236
+ * Only lighthouserc-config.json's top-level forced-reflow setting is read by
237
+ * check-lighthouse-details.mjs. Other filenames and audits have no inferred
238
+ * baseline. The real checker/comparator boundary is covered by a parity test.
239
+ * @param {string} relPath Repo-relative path
240
+ * @param {unknown} base Parsed baseline config
241
+ * @param {unknown} current Parsed current config
242
+ * @returns {Finding[]} Removed or weakened assertions
243
+ */
244
+ function compareLighthouse(relPath, base, current) {
245
+ const baseline = extractLighthouseAssertions(base);
246
+ const updated = extractLighthouseAssertions(current);
247
+ const findings = compareConstraints(relPath, baseline, updated);
248
+ const previous = base?.assertions?.forcedReflowInsight?.maxNumericValue;
249
+ const added = current?.assertions?.forcedReflowInsight?.maxNumericValue;
250
+ if (
251
+ relPath.split("/").at(-1) === "lighthouserc-config.json" &&
252
+ (previous == null ||
253
+ base?.ci?.assert?.assertions != null ||
254
+ current?.ci?.assert?.assertions != null) &&
255
+ (previous == null ||
256
+ (typeof previous === "number" && Number.isFinite(previous))) &&
257
+ typeof added === "number" &&
258
+ Number.isFinite(added)
259
+ ) {
260
+ // This checker reads top-level settings even beside canonical assertions.
261
+ // Keep its comparison separate so a new setting cannot replace a canonical
262
+ // bound with the same audit name and hide that bound's weakening.
263
+ const key = "forcedReflowInsight.maxNumericValue";
264
+ findings.push(
265
+ ...compareConstraints(
266
+ relPath,
267
+ new Map([[key, { value: previous ?? 100, direction: "max" }]]),
268
+ new Map([[key, { value: added, direction: "max" }]])
269
+ )
270
+ );
271
+ }
272
+ return findings;
273
+ }
274
+
234
275
  /**
235
276
  * Compare one watched file's baseline and current contents and report every
236
277
  * weakening. Pure: no filesystem or git access.
@@ -301,11 +342,7 @@ export function compareFile(relPath, baselineText, currentText) {
301
342
  case "k6":
302
343
  return compareK6(relPath, base, current);
303
344
  case "lighthouse":
304
- return compareConstraints(
305
- relPath,
306
- extractLighthouseAssertions(base),
307
- extractLighthouseAssertions(current)
308
- );
345
+ return compareLighthouse(relPath, base, current);
309
346
  case KIND_ALLOW_LIST:
310
347
  return compareAllowList(relPath, base, current);
311
348
  default:
@@ -234,6 +234,47 @@ function compareAllowList(relPath, base, current) {
234
234
  return findings;
235
235
  }
236
236
 
237
+ /**
238
+ * Compare Lighthouse assertions, including the shipped detail checker's default.
239
+ * Only lighthouserc-config.json's top-level forced-reflow setting is read by
240
+ * check-lighthouse-details.mjs. Other filenames and audits have no inferred
241
+ * baseline. The real checker/comparator boundary is covered by a parity test.
242
+ * @param {string} relPath Repo-relative path
243
+ * @param {unknown} base Parsed baseline config
244
+ * @param {unknown} current Parsed current config
245
+ * @returns {Finding[]} Removed or weakened assertions
246
+ */
247
+ function compareLighthouse(relPath, base, current) {
248
+ const baseline = extractLighthouseAssertions(base);
249
+ const updated = extractLighthouseAssertions(current);
250
+ const findings = compareConstraints(relPath, baseline, updated);
251
+ const previous = base?.assertions?.forcedReflowInsight?.maxNumericValue;
252
+ const added = current?.assertions?.forcedReflowInsight?.maxNumericValue;
253
+ if (
254
+ relPath.split("/").at(-1) === "lighthouserc-config.json" &&
255
+ (previous == null ||
256
+ base?.ci?.assert?.assertions != null ||
257
+ current?.ci?.assert?.assertions != null) &&
258
+ (previous == null ||
259
+ (typeof previous === "number" && Number.isFinite(previous))) &&
260
+ typeof added === "number" &&
261
+ Number.isFinite(added)
262
+ ) {
263
+ // This checker reads top-level settings even beside canonical assertions.
264
+ // Keep its comparison separate so a new setting cannot replace a canonical
265
+ // bound with the same audit name and hide that bound's weakening.
266
+ const key = "forcedReflowInsight.maxNumericValue";
267
+ findings.push(
268
+ ...compareConstraints(
269
+ relPath,
270
+ new Map([[key, { value: previous ?? 100, direction: "max" }]]),
271
+ new Map([[key, { value: added, direction: "max" }]])
272
+ )
273
+ );
274
+ }
275
+ return findings;
276
+ }
277
+
237
278
  /**
238
279
  * Compare one watched file's baseline and current contents and report every
239
280
  * weakening. Pure: no filesystem or git access.
@@ -304,11 +345,7 @@ export function compareFile(relPath, baselineText, currentText) {
304
345
  case "k6":
305
346
  return compareK6(relPath, base, current);
306
347
  case "lighthouse":
307
- return compareConstraints(
308
- relPath,
309
- extractLighthouseAssertions(base),
310
- extractLighthouseAssertions(current)
311
- );
348
+ return compareLighthouse(relPath, base, current);
312
349
  case KIND_ALLOW_LIST:
313
350
  return compareAllowList(relPath, base, current);
314
351
  default:
@@ -1848,11 +1848,20 @@ export const parseChangedLineRanges = patch => {
1848
1848
  * @param {string} cwd - Project root.
1849
1849
  * @param {string} base - Merge-base sha.
1850
1850
  * @param {string} file - Repository-relative path.
1851
+ * @param {string} [previousFile] - Old path when the file was renamed.
1851
1852
  * @returns {string[]} `path:start-end` entries for current changed lines.
1852
1853
  */
1853
- export const selectChangedLineRanges = (cwd, base, file) =>
1854
+ export const selectChangedLineRanges = (cwd, base, file, previousFile = file) =>
1854
1855
  parseChangedLineRanges(
1855
- git(cwd, ["diff", "--unified=0", "--diff-filter=ACMR", base, "--", file])
1856
+ git(cwd, [
1857
+ "diff",
1858
+ "--find-renames",
1859
+ "--unified=0",
1860
+ "--diff-filter=ACMR",
1861
+ previousFile === file ? base : `${base}:${previousFile}`,
1862
+ "--",
1863
+ file,
1864
+ ])
1856
1865
  ).map(({ start, end }) => `${file}:${start}-${end}`);
1857
1866
 
1858
1867
  /**
@@ -1870,16 +1879,35 @@ export const selectChangedTargets = (cwd, base, patterns) => {
1870
1879
  // a target whose only change is uncommitted is invisible to committed state,
1871
1880
  // so the gate printed "0 mutate targets" and exited 0 while Stryker, pointed
1872
1881
  // at the same tree, had a changed target in front of it.
1873
- const changed = git(cwd, ["diff", "--name-only", "--diff-filter=ACMRD", base])
1874
- .split("\n")
1875
- .map(file => file.trim())
1876
- .filter(Boolean);
1877
- const selectedFiles = changed
1878
- .filter(file => isMutateTarget(file, patterns))
1879
- .filter(file => fs.existsSync(path.join(cwd, file)));
1880
- const byFile = selectedFiles.map(file => ({
1882
+ // Split full rewrites so an old name reused after a move remains a possible
1883
+ // source. Include B as well as M: Git filters rewritten source records as B.
1884
+ const names = git(cwd, [
1885
+ "diff",
1886
+ "--find-renames",
1887
+ "--name-status",
1888
+ "--break-rewrites",
1889
+ "-z",
1890
+ "--diff-filter=ACMRDB",
1891
+ base,
1892
+ ]).split("\0");
1893
+ const changed = [];
1894
+ for (let index = 0; names[index]; ) {
1895
+ const status = names[index++];
1896
+ const previousFile = names[index++];
1897
+ const file = /^[RC]/u.test(status) ? names[index++] : previousFile;
1898
+ changed.push({ file, previousFile });
1899
+ }
1900
+ const selectedFiles = changed.filter(({ file }) =>
1901
+ isMutateTarget(file, patterns)
1902
+ );
1903
+ const byFile = selectedFiles.map(({ file, previousFile }) => ({
1881
1904
  file,
1882
- ranges: selectChangedLineRanges(cwd, base, file),
1905
+ // Preserve deleted targets for classification, without asking Stryker to
1906
+ // open them. A rename compares the old blob with the current destination;
1907
+ // diffing both paths together can include a new file reusing the old name.
1908
+ ranges: fs.existsSync(path.join(cwd, file))
1909
+ ? selectChangedLineRanges(cwd, base, file, previousFile)
1910
+ : [],
1883
1911
  }));
1884
1912
  return {
1885
1913
  changed: changed.length,
@@ -1890,7 +1918,7 @@ export const selectChangedTargets = (cwd, base, patterns) => {
1890
1918
  .map(entry => entry.file),
1891
1919
  // Reported from the diff, not from the selection, because by construction
1892
1920
  // these can never BE in the selection — that is the whole point of them.
1893
- uninstrumentable: uninstrumentableGuards(changed),
1921
+ uninstrumentable: uninstrumentableGuards(changed.map(({ file }) => file)),
1894
1922
  };
1895
1923
  };
1896
1924
 
@@ -234,6 +234,47 @@ function compareAllowList(relPath, base, current) {
234
234
  return findings;
235
235
  }
236
236
 
237
+ /**
238
+ * Compare Lighthouse assertions, including the shipped detail checker's default.
239
+ * Only lighthouserc-config.json's top-level forced-reflow setting is read by
240
+ * check-lighthouse-details.mjs. Other filenames and audits have no inferred
241
+ * baseline. The real checker/comparator boundary is covered by a parity test.
242
+ * @param {string} relPath Repo-relative path
243
+ * @param {unknown} base Parsed baseline config
244
+ * @param {unknown} current Parsed current config
245
+ * @returns {Finding[]} Removed or weakened assertions
246
+ */
247
+ function compareLighthouse(relPath, base, current) {
248
+ const baseline = extractLighthouseAssertions(base);
249
+ const updated = extractLighthouseAssertions(current);
250
+ const findings = compareConstraints(relPath, baseline, updated);
251
+ const previous = base?.assertions?.forcedReflowInsight?.maxNumericValue;
252
+ const added = current?.assertions?.forcedReflowInsight?.maxNumericValue;
253
+ if (
254
+ relPath.split("/").at(-1) === "lighthouserc-config.json" &&
255
+ (previous == null ||
256
+ base?.ci?.assert?.assertions != null ||
257
+ current?.ci?.assert?.assertions != null) &&
258
+ (previous == null ||
259
+ (typeof previous === "number" && Number.isFinite(previous))) &&
260
+ typeof added === "number" &&
261
+ Number.isFinite(added)
262
+ ) {
263
+ // This checker reads top-level settings even beside canonical assertions.
264
+ // Keep its comparison separate so a new setting cannot replace a canonical
265
+ // bound with the same audit name and hide that bound's weakening.
266
+ const key = "forcedReflowInsight.maxNumericValue";
267
+ findings.push(
268
+ ...compareConstraints(
269
+ relPath,
270
+ new Map([[key, { value: previous ?? 100, direction: "max" }]]),
271
+ new Map([[key, { value: added, direction: "max" }]])
272
+ )
273
+ );
274
+ }
275
+ return findings;
276
+ }
277
+
237
278
  /**
238
279
  * Compare one watched file's baseline and current contents and report every
239
280
  * weakening. Pure: no filesystem or git access.
@@ -304,11 +345,7 @@ export function compareFile(relPath, baselineText, currentText) {
304
345
  case "k6":
305
346
  return compareK6(relPath, base, current);
306
347
  case "lighthouse":
307
- return compareConstraints(
308
- relPath,
309
- extractLighthouseAssertions(base),
310
- extractLighthouseAssertions(current)
311
- );
348
+ return compareLighthouse(relPath, base, current);
312
349
  case KIND_ALLOW_LIST:
313
350
  return compareAllowList(relPath, base, current);
314
351
  default: