@codyswann/lisa 4.45.2 → 4.45.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +115 -12
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +4 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +9 -4
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/parity-safety-net.sh +115 -12
- package/package.json +4 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/hooks/parity-safety-net.sh +115 -12
- package/plugins/lisa-agy/hooks/parity-safety-net.sh +115 -12
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/hooks/parity-safety-net.sh +115 -12
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/parity-safety-net.sh +115 -12
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/hooks/parity-safety-net.sh +115 -12
- package/scripts/check-typecheck-tests.mjs +229 -72
- package/scripts/lib/dependency-tree.mjs +136 -0
- package/typescript/copy-contents/.husky/pre-push +45 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dependency-tree — decide whether a gate's dependency tree is resolvable, and
|
|
3
|
+
* say "cannot measure" in one voice when it is not (CodySwannGT/lisa#3913).
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* ## The defect this exists for
|
|
7
|
+
*
|
|
8
|
+
* The `type-correctness` gate spawns the compiler by PATH:
|
|
9
|
+
* `node node_modules/typescript/bin/tsc`. With an empty `node_modules` the
|
|
10
|
+
* SPAWN still succeeds — node starts, and it is node that then cannot find the
|
|
11
|
+
* module — so the gate's `if (tsc.error)` guard does not fire. node's
|
|
12
|
+
* "Cannot find module" goes to stderr and does not match the gate's
|
|
13
|
+
* `file(line,col): error TSxxxx:` pattern, so the parsed-diagnostics map comes
|
|
14
|
+
* back EMPTY. Every quarantined file then satisfies "has no errors", and the
|
|
15
|
+
* gate reports:
|
|
16
|
+
*
|
|
17
|
+
* ```
|
|
18
|
+
* ❌ 370 quarantined file(s) now type-check and must leave the list:
|
|
19
|
+
* Remove them from typecheck-quarantine.json.
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Following that deletes 370 live quarantine entries on the word of a checker
|
|
23
|
+
* that compiled nothing. The comparison was not wrong — it was correct about an
|
|
24
|
+
* input it was never entitled to accept.
|
|
25
|
+
*
|
|
26
|
+
* ## Why "cannot measure" is a THIRD outcome, not a failure message
|
|
27
|
+
*
|
|
28
|
+
* This is the #3888 family: a control that could not establish its subject must
|
|
29
|
+
* not render identically to one that established it and found nothing. The
|
|
30
|
+
* sibling exemplar is the review gate's `UNDETERMINED` verdict in
|
|
31
|
+
* `check-skipped-required-checks.mjs`, whose own comment states the rule this
|
|
32
|
+
* module follows — resolving an unestablished subject to `success` "would be a
|
|
33
|
+
* new instance of exactly that".
|
|
34
|
+
*
|
|
35
|
+
* A gate whose only surface is an exit code cannot emit a third code that
|
|
36
|
+
* anything reads, so the fallback is fixed: **fail closed, with the denial as
|
|
37
|
+
* the first clause.** Never pass. A reader who skims one line must come away
|
|
38
|
+
* knowing the finding was NOT made, because the natural inference from silence
|
|
39
|
+
* about errors is that there were none.
|
|
40
|
+
*
|
|
41
|
+
* ## The message contract
|
|
42
|
+
*
|
|
43
|
+
* {@link cannotMeasure} takes the clauses rather than a finished string so that
|
|
44
|
+
* no call site can ship three of the four. Every message names:
|
|
45
|
+
*
|
|
46
|
+
* 1. the outcome, in a distinct word (`CANNOT MEASURE`);
|
|
47
|
+
* 2. the inference a reader would otherwise draw, DENIED in words;
|
|
48
|
+
* 3. why the measurement could not happen;
|
|
49
|
+
* 4. what to do — including, where one exists, the destructive remedy that
|
|
50
|
+
* must NOT be followed.
|
|
51
|
+
*
|
|
52
|
+
* Clause 2 is the one that is easy to drop and the only one that stops a
|
|
53
|
+
* destructive edit, so it is a required parameter.
|
|
54
|
+
*
|
|
55
|
+
* @module scripts/lib/dependency-tree
|
|
56
|
+
*/
|
|
57
|
+
import { existsSync } from "node:fs";
|
|
58
|
+
import path from "node:path";
|
|
59
|
+
|
|
60
|
+
/** The install command that repairs an unresolvable tree. */
|
|
61
|
+
export const INSTALL_COMMAND = "bun install --frozen-lockfile";
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* The distinct outcome word. Deliberately not "ERROR" or "FAILED": those are
|
|
65
|
+
* what the gate prints when it DID measure and found something, which is the
|
|
66
|
+
* confusion this whole module exists to prevent.
|
|
67
|
+
*/
|
|
68
|
+
export const CANNOT_MEASURE = "CANNOT MEASURE";
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Names the dependencies a gate needs that are not present under `root`.
|
|
72
|
+
*
|
|
73
|
+
* Presence is tested at the exact path the gate will spawn or import, not by
|
|
74
|
+
* asking whether `node_modules` exists. A partially installed tree — the case
|
|
75
|
+
* that produced the `knip` sibling of this defect, where `node_modules` was
|
|
76
|
+
* present but two binaries were not — has a `node_modules` directory and still
|
|
77
|
+
* cannot answer the question.
|
|
78
|
+
*
|
|
79
|
+
* @param {string} root - Directory the gate resolves dependencies against.
|
|
80
|
+
* @param {ReadonlyArray<string>} relativePaths - Paths under `root` to require,
|
|
81
|
+
* each already spelled the way the gate will use it.
|
|
82
|
+
* @returns {string[]} The missing paths, in the order given.
|
|
83
|
+
*/
|
|
84
|
+
export function missingDependencies(root, relativePaths) {
|
|
85
|
+
return relativePaths.filter(
|
|
86
|
+
relative => !existsSync(path.join(root, relative))
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* True when a child process signalled failure without producing anything the
|
|
92
|
+
* caller could read as a finding.
|
|
93
|
+
*
|
|
94
|
+
* This is the general form of the defect, and it catches more than an empty
|
|
95
|
+
* `node_modules`: a broken `tsconfig`, an out-of-memory compiler, a crash. The
|
|
96
|
+
* three cases are distinguishable in principle and identical in what they
|
|
97
|
+
* license — nothing.
|
|
98
|
+
*
|
|
99
|
+
* The one ambiguous input resolves the safe way. If a compiler ever emitted
|
|
100
|
+
* real diagnostics in a format the caller's pattern did not match, this reports
|
|
101
|
+
* "could not measure" rather than "no errors" — and "I could not read the
|
|
102
|
+
* output" is the honest account of that too.
|
|
103
|
+
*
|
|
104
|
+
* A zero exit with no diagnostics is NOT this: that is a clean run, and the
|
|
105
|
+
* caller is entitled to report it.
|
|
106
|
+
*
|
|
107
|
+
* @param {number | null} status - The child's exit status.
|
|
108
|
+
* @param {number} findingCount - How many findings the caller parsed out.
|
|
109
|
+
* @returns {boolean} Whether the run was vacuous.
|
|
110
|
+
*/
|
|
111
|
+
export function ranVacuously(status, findingCount) {
|
|
112
|
+
return status !== 0 && findingCount === 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Builds the operator-readable `CANNOT MEASURE` block.
|
|
117
|
+
*
|
|
118
|
+
* Returned rather than printed so callers can route it to stderr, a report, or
|
|
119
|
+
* a test assertion without this module deciding.
|
|
120
|
+
*
|
|
121
|
+
* @param {object} clauses - The four required clauses.
|
|
122
|
+
* @param {string} clauses.gate - The gate's own name, as it prints elsewhere.
|
|
123
|
+
* @param {string} clauses.denial - What this is NOT reporting, phrased as the
|
|
124
|
+
* inference a reader would otherwise draw. Required: it is the clause that
|
|
125
|
+
* stops a destructive edit.
|
|
126
|
+
* @param {string} clauses.because - Why the measurement could not happen.
|
|
127
|
+
* @param {string} clauses.remedy - What the reader should do instead.
|
|
128
|
+
* @returns {string} The block, newline-separated, no trailing newline.
|
|
129
|
+
*/
|
|
130
|
+
export function cannotMeasure({ gate, denial, because, remedy }) {
|
|
131
|
+
return [
|
|
132
|
+
`${CANNOT_MEASURE} — ${gate} did not run, and is NOT reporting ${denial}.`,
|
|
133
|
+
`Why: ${because}`,
|
|
134
|
+
`Do this: ${remedy}`,
|
|
135
|
+
].join("\n");
|
|
136
|
+
}
|
|
@@ -126,6 +126,51 @@ if ! command -v jq >/dev/null 2>&1; then
|
|
|
126
126
|
exit 1
|
|
127
127
|
fi
|
|
128
128
|
|
|
129
|
+
# The DEPENDENCY TREE is proved here too, for the same reason and one worse
|
|
130
|
+
# consequence (CodySwannGT/lisa#3913).
|
|
131
|
+
#
|
|
132
|
+
# Every gate below resolves its tool out of `node_modules` — knip, vitest, tsc.
|
|
133
|
+
# An empty tree does not stop those gates; it makes them answer from nothing,
|
|
134
|
+
# and an empty answer is not silent. Upstream, the `type-correctness` gate is
|
|
135
|
+
# what showed this belongs here rather than inside each gate: with no compiler
|
|
136
|
+
# to run it parsed zero diagnostics, concluded from that emptiness that every
|
|
137
|
+
# quarantined file now compiles, and instructed a reader to delete the
|
|
138
|
+
# quarantine entries protecting them — a destructive edit ordered by a control
|
|
139
|
+
# whose inputs never resolved. Its sibling `knip:check` reports unlisted
|
|
140
|
+
# binaries from the identical cause. That one merely LOOKS odd and nobody acts
|
|
141
|
+
# on it, which is exactly why it went unfixed while the dangerous one hid
|
|
142
|
+
# behind it.
|
|
143
|
+
#
|
|
144
|
+
# So this is not a convenience check for a missing install. Absence of the
|
|
145
|
+
# dependencies and absence of findings must not produce the same observable. A
|
|
146
|
+
# check that cannot RUN is not a skip and not a pass — it blocks.
|
|
147
|
+
if [ -f package.json ]; then
|
|
148
|
+
LISA_DECLARED_DEPS="$(jq -r '((.dependencies // {}) + (.devDependencies // {})) | length' package.json 2>/dev/null)"
|
|
149
|
+
# A non-numeric or absent answer counts as zero: this guard may not be the
|
|
150
|
+
# thing that blocks a push over an unreadable package.json.
|
|
151
|
+
case "$LISA_DECLARED_DEPS" in
|
|
152
|
+
"" | *[!0-9]*) LISA_DECLARED_DEPS=0 ;;
|
|
153
|
+
esac
|
|
154
|
+
# `ls -A` covers absent and present-but-empty in one test, which is the
|
|
155
|
+
# distinction the gates themselves cannot make.
|
|
156
|
+
if [ "$LISA_DECLARED_DEPS" -gt 0 ] && [ -z "$(ls -A node_modules 2>/dev/null)" ]; then
|
|
157
|
+
echo "❌ Push blocked: CANNOT MEASURE — dependencies are not installed."
|
|
158
|
+
echo ""
|
|
159
|
+
echo " package.json declares $LISA_DECLARED_DEPS dependencies and node_modules is"
|
|
160
|
+
echo " absent or empty, so the gates below cannot resolve the tools they"
|
|
161
|
+
echo " run: tsc, knip and vitest."
|
|
162
|
+
echo ""
|
|
163
|
+
echo " This is NOT a finding about your code, and nothing below it is"
|
|
164
|
+
echo " either."
|
|
165
|
+
echo ""
|
|
166
|
+
echo "To fix:"
|
|
167
|
+
echo " bun install --frozen-lockfile # or your package manager's equivalent"
|
|
168
|
+
echo ""
|
|
169
|
+
exit 1
|
|
170
|
+
fi
|
|
171
|
+
unset LISA_DECLARED_DEPS
|
|
172
|
+
fi
|
|
173
|
+
|
|
129
174
|
# BEGIN: push destination guard
|
|
130
175
|
# ---------------------------------------------------------------------------
|
|
131
176
|
# Refuse a push whose RESOLVED destination is a deploy branch it was not aimed
|