@codyswann/lisa 4.4.14 → 4.4.16

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/lib/placeholder-expiry.mjs +79 -7
  2. package/all/copy-overwrite/scripts/lisa-floor-collisions.mjs +46 -9
  3. package/all/copy-overwrite/scripts/lisa-postinstall.mjs +10 -1
  4. package/all/copy-overwrite/scripts/lisa-reconcile-policy.mjs +260 -41
  5. package/all/copy-overwrite/scripts/lisa-schema-validate.mjs +12 -1
  6. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  7. package/dist/core/lisa-owned-hash-ledger.js +17 -0
  8. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  9. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  10. package/dist/core/upstream-evidence-manifest.js +19 -14
  11. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  12. package/package.json +2 -1
  13. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  14. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  15. package/plugins/lisa/.codex-plugin/skills/lisa-improve-test-coverage/SKILL.md +4 -1
  16. package/plugins/lisa/.codex-plugin/skills/lisa-improve-tests/SKILL.md +4 -1
  17. package/plugins/lisa/.codex-plugin/skills/lisa-nightly-lower-code-complexity/SKILL.md +10 -2
  18. package/plugins/lisa/rules/eager/falsifiable-checks.md +16 -1
  19. package/plugins/lisa/rules/reference/falsifiable-checks.md +74 -1
  20. package/plugins/lisa/skills/lisa-improve-test-coverage/SKILL.md +4 -1
  21. package/plugins/lisa/skills/lisa-improve-tests/SKILL.md +4 -1
  22. package/plugins/lisa/skills/lisa-nightly-lower-code-complexity/SKILL.md +10 -2
  23. package/plugins/lisa-agy/plugin.json +1 -1
  24. package/plugins/lisa-agy/skills/lisa-improve-test-coverage/SKILL.md +4 -1
  25. package/plugins/lisa-agy/skills/lisa-improve-tests/SKILL.md +4 -1
  26. package/plugins/lisa-agy/skills/lisa-nightly-lower-code-complexity/SKILL.md +10 -2
  27. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  29. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  30. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-copilot/rules/eager/falsifiable-checks.md +16 -1
  34. package/plugins/lisa-copilot/rules/reference/falsifiable-checks.md +74 -1
  35. package/plugins/lisa-copilot/skills/lisa-improve-test-coverage/SKILL.md +4 -1
  36. package/plugins/lisa-copilot/skills/lisa-improve-tests/SKILL.md +4 -1
  37. package/plugins/lisa-copilot/skills/lisa-nightly-lower-code-complexity/SKILL.md +10 -2
  38. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-cursor/rules/falsifiable-checks-reference.mdc +74 -1
  40. package/plugins/lisa-cursor/rules/falsifiable-checks.mdc +16 -1
  41. package/plugins/lisa-cursor/skills/lisa-improve-test-coverage/SKILL.md +4 -1
  42. package/plugins/lisa-cursor/skills/lisa-improve-tests/SKILL.md +4 -1
  43. package/plugins/lisa-cursor/skills/lisa-nightly-lower-code-complexity/SKILL.md +10 -2
  44. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  45. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  46. package/plugins/lisa-expo-agy/plugin.json +1 -1
  47. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  52. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  56. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  57. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  61. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  62. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  66. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  67. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  71. package/plugins/lisa-rails/.codex-plugin/skills/improve-code-complexity/SKILL.md +4 -1
  72. package/plugins/lisa-rails/.codex-plugin/skills/improve-test-coverage/SKILL.md +4 -1
  73. package/plugins/lisa-rails/.codex-plugin/skills/ops-verify-telemetry/SKILL.md +30 -1
  74. package/plugins/lisa-rails/skills/improve-code-complexity/SKILL.md +4 -1
  75. package/plugins/lisa-rails/skills/improve-test-coverage/SKILL.md +4 -1
  76. package/plugins/lisa-rails/skills/ops-verify-telemetry/SKILL.md +30 -1
  77. package/plugins/lisa-rails-agy/plugin.json +1 -1
  78. package/plugins/lisa-rails-agy/skills/improve-code-complexity/SKILL.md +4 -1
  79. package/plugins/lisa-rails-agy/skills/improve-test-coverage/SKILL.md +4 -1
  80. package/plugins/lisa-rails-agy/skills/ops-verify-telemetry/SKILL.md +30 -1
  81. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-rails-copilot/skills/improve-code-complexity/SKILL.md +4 -1
  83. package/plugins/lisa-rails-copilot/skills/improve-test-coverage/SKILL.md +4 -1
  84. package/plugins/lisa-rails-copilot/skills/ops-verify-telemetry/SKILL.md +30 -1
  85. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-rails-cursor/skills/improve-code-complexity/SKILL.md +4 -1
  87. package/plugins/lisa-rails-cursor/skills/improve-test-coverage/SKILL.md +4 -1
  88. package/plugins/lisa-rails-cursor/skills/ops-verify-telemetry/SKILL.md +30 -1
  89. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  91. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  92. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  93. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  94. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  95. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  96. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  97. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  98. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  99. package/plugins/src/base/rules/eager/falsifiable-checks.md +16 -1
  100. package/plugins/src/base/rules/reference/falsifiable-checks.md +74 -1
  101. package/plugins/src/base/skills/lisa-improve-test-coverage/SKILL.md +4 -1
  102. package/plugins/src/base/skills/lisa-improve-tests/SKILL.md +4 -1
  103. package/plugins/src/base/skills/lisa-nightly-lower-code-complexity/SKILL.md +10 -2
  104. package/plugins/src/rails/skills/improve-code-complexity/SKILL.md +4 -1
  105. package/plugins/src/rails/skills/improve-test-coverage/SKILL.md +4 -1
  106. package/plugins/src/rails/skills/ops-verify-telemetry/SKILL.md +30 -1
  107. package/scripts/check-pipeline-status-reads.mjs +684 -0
  108. package/typescript/copy-overwrite/scripts/lisa-mutation.mjs +75 -25
@@ -147,6 +147,7 @@ export const OUTCOMES = Object.freeze({
147
147
  nothingToMutate: "mutation-gate: nothing-to-mutate",
148
148
  inertConfig: "mutation-gate: inert-mutate-config",
149
149
  unrepresentablePath: "mutation-gate: unrepresentable-path",
150
+ diffFailed: "mutation-gate: diff-failed",
150
151
  scoped: "mutation-gate: scoped-run",
151
152
  wholeList: "mutation-gate: whole-list-run",
152
153
  dryRunTimeout: "mutation-gate: dry-run-timeout",
@@ -1467,31 +1468,45 @@ kill -9 "$1" 2>/dev/null || true
1467
1468
  * holds `tee` open for the WHOLE deadline after Stryker has finished, turning
1468
1469
  * every successful run into a two-hour hang. Measured the hard way.
1469
1470
  *
1470
- * The program and every path argument still travel as argv through `"$0" "$@"`.
1471
+ * The program and every path argument travel as argv through `"$0" "$@"`.
1471
1472
  * Interpolating them would put a filename through the shell's word splitting,
1472
1473
  * which is how a path with a space becomes two paths that do not exist.
1473
- * @param {string} statusPath - File the wrapper writes the exit code into.
1474
- * @param {string} logPath - File the wrapper tees the output into.
1475
- * @param {string} killedPath - File the watchdog writes when it fires.
1474
+ *
1475
+ * That was a promise this function did not keep (CodySwannGT/lisa#3029). The
1476
+ * three scratch paths were single-quoted straight into the script text, and all
1477
+ * three derive from `mkdtempSync(path.join(os.tmpdir(), …))`, so all three carry
1478
+ * `TMPDIR`. A `TMPDIR` containing a single quote closed the quote and handed the
1479
+ * remainder of the path to the shell as syntax. They now arrive as `$1`, `$2`
1480
+ * and `$3` and are shifted off before `"$@"` is expanded, so the paragraph above
1481
+ * describes the code.
1482
+ *
1483
+ * The deadline is still interpolated, and that is not an exception to the rule:
1484
+ * `seconds` is the output of `Math.max(1, Math.ceil(…))`, so it is a number by
1485
+ * construction and carries nothing to word-split. The rule is about PATHS,
1486
+ * which is where the untrusted bytes are.
1476
1487
  * @param {number} deadlineMs - How long Stryker may run.
1477
- * @returns {string} The script.
1488
+ * @returns {string} The script, which reads its three paths from argv.
1478
1489
  */
1479
- export const watchdogScript = (statusPath, logPath, killedPath, deadlineMs) => {
1490
+ export const watchdogScript = deadlineMs => {
1480
1491
  const seconds = Math.max(1, Math.ceil(deadlineMs / 1000));
1481
- return `${REAP_FUNCTION}{ set -m 2>/dev/null || true
1492
+ return `${REAP_FUNCTION}lisa_gate_status="$1"
1493
+ lisa_gate_log="$2"
1494
+ lisa_gate_killed="$3"
1495
+ shift 3
1496
+ { set -m 2>/dev/null || true
1482
1497
  "$0" "$@" &
1483
1498
  lisa_gate_child=$!
1484
1499
  ( sleep ${seconds}
1485
- : > '${killedPath}'
1500
+ : > "$lisa_gate_killed"
1486
1501
  kill -9 -"$lisa_gate_child" 2>/dev/null
1487
1502
  lisa_gate_reap "$lisa_gate_child"
1488
1503
  ) >/dev/null 2>&1 </dev/null &
1489
1504
  lisa_gate_watchdog=$!
1490
1505
  set +m 2>/dev/null || true
1491
1506
  wait "$lisa_gate_child"
1492
- echo $? > '${statusPath}'
1507
+ echo $? > "$lisa_gate_status"
1493
1508
  kill -9 "$lisa_gate_watchdog" 2>/dev/null || true
1494
- } 2>&1 | tee '${logPath}'
1509
+ } 2>&1 | tee "$lisa_gate_log"
1495
1510
  `;
1496
1511
  };
1497
1512
 
@@ -1533,6 +1548,14 @@ const runStrykerPlain = (cwd, entry, env, deadlineMs) => {
1533
1548
  * space becomes two paths that do not exist — and Stryker would then mutate
1534
1549
  * neither, find nothing, and exit 0.
1535
1550
  *
1551
+ * That promise used to cover only Stryker's own arguments. The two scratch
1552
+ * paths were single-quoted straight into the script text, and both derive from
1553
+ * `mkdtempSync(path.join(os.tmpdir(), …))`, so both carry `TMPDIR` — attacker-
1554
+ * adjacent on a shared machine and merely hostile on a normal one. A `TMPDIR`
1555
+ * containing a single quote closed the quote and handed the rest of the path to
1556
+ * the shell as syntax. They now arrive as `$1` and `$2` and are shifted off
1557
+ * before `"$@"` is expanded, so the doc comment above describes the code.
1558
+ *
1536
1559
  * The exit code comes from a status file written INSIDE the pipeline, never
1537
1560
  * from the pipeline itself: a pipeline reports `tee`'s status, which is
1538
1561
  * essentially always zero, and reading it would report every failing gate as
@@ -1555,20 +1578,32 @@ const runStrykerCaptured = (cwd, entry, env, deadlineMs) => {
1555
1578
  const logPath = path.join(dir, "stryker.log");
1556
1579
  const statusPath = path.join(dir, "status");
1557
1580
  const killedPath = path.join(dir, "killed");
1558
- const script = watchdogScript(statusPath, logPath, killedPath, deadlineMs);
1581
+ const script = watchdogScript(deadlineMs);
1559
1582
  try {
1560
- const child = spawnSync("sh", ["-c", script, entry.file, ...entry.args], {
1561
- cwd,
1562
- stdio: "inherit",
1563
- env,
1564
- killSignal: "SIGKILL",
1565
- // A backstop under the wrapper's own watchdog, not the bound. The
1566
- // wrapper kills STRYKER; this kills the shell, which leaves Stryker
1567
- // running until its next write hits a broken pipe — and a hung run has
1568
- // no next write. The grace is what keeps the two from racing, so the
1569
- // failure that gets reported is the one that names the real child.
1570
- timeout: deadlineMs + WATCHDOG_GRACE_MS,
1571
- });
1583
+ const child = spawnSync(
1584
+ "sh",
1585
+ [
1586
+ "-c",
1587
+ script,
1588
+ entry.file,
1589
+ statusPath,
1590
+ logPath,
1591
+ killedPath,
1592
+ ...entry.args,
1593
+ ],
1594
+ {
1595
+ cwd,
1596
+ stdio: "inherit",
1597
+ env,
1598
+ killSignal: "SIGKILL",
1599
+ // A backstop under the wrapper's own watchdog, not the bound. The
1600
+ // wrapper kills STRYKER; this kills the shell, which leaves Stryker
1601
+ // running until its next write hits a broken pipe — and a hung run has
1602
+ // no next write. The grace is what keeps the two from racing, so the
1603
+ // failure that gets reported is the one that names the real child.
1604
+ timeout: deadlineMs + WATCHDOG_GRACE_MS,
1605
+ }
1606
+ );
1572
1607
  if (fs.existsSync(killedPath) || child.error?.code === "ETIMEDOUT") {
1573
1608
  return {
1574
1609
  code: 1,
@@ -1773,8 +1808,23 @@ export const runGate = (cwd = process.cwd(), argv = []) => {
1773
1808
  try {
1774
1809
  scope = selectChangedTargets(cwd, base, patterns);
1775
1810
  } catch (error) {
1776
- console.error(`⚠️ Could not compute changed files: ${error.message}`);
1777
- return 0;
1811
+ // Was a warning and an exit 0, with no outcome marker — the only exit in
1812
+ // this module shaped that way. Both halves were wrong in the same
1813
+ // direction. A git prerequisite that failed AFTER a merge-base resolved is
1814
+ // an anomaly, not a clean tree, and reporting it as a pass is the silent
1815
+ // green this whole file exists to refuse. The marker matters just as much:
1816
+ // a test asserting the gate did not no-op could not observe this path at
1817
+ // all, so the one exit that lied was also the one exit nothing could see.
1818
+ //
1819
+ // The genuinely-cannot-measure cases are already handled above and keep
1820
+ // their exit 0: a disabled gate, and a merge-base that does not resolve.
1821
+ console.error(
1822
+ `❌ ${OUTCOMES.diffFailed}\n` +
1823
+ ` Could not compute the files changed vs ${since}: ${error.message}\n` +
1824
+ " NO mutant was generated and NO score was computed. Nothing was measured,\n" +
1825
+ " so nothing passed."
1826
+ );
1827
+ return 1;
1778
1828
  }
1779
1829
 
1780
1830
  if (scope.selected.length === 0) {