@codyswann/lisa 2.342.0 → 2.342.2
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-floor-collisions.mjs +38 -6
- package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +44 -13
- package/all/create-only/scripts/remote-agent-aws-setup.sh +8 -1
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +8 -7
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/parity-safety-net.sh +44 -13
- package/package.json +1 -1
- 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 +44 -13
- package/plugins/lisa/hooks/threshold-ratchet.mjs +39 -5
- package/plugins/lisa-agy/hooks/parity-safety-net.sh +44 -13
- 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 +44 -13
- package/plugins/lisa-copilot/hooks/threshold-ratchet.mjs +39 -5
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/parity-safety-net.sh +44 -13
- package/plugins/lisa-cursor/hooks/threshold-ratchet.mjs +39 -5
- 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 +44 -13
- package/plugins/src/base/hooks/threshold-ratchet.mjs +39 -5
- package/rails/copy-overwrite/scripts/check-threshold-ratchet.mjs +39 -5
- package/typescript/copy-overwrite/scripts/check-threshold-ratchet.mjs +39 -5
|
@@ -56,6 +56,15 @@ const GIT = GIT_LOCATIONS.find(candidate => fs.existsSync(candidate)) ?? "git";
|
|
|
56
56
|
|
|
57
57
|
/** Git flag shared by every changed-file listing. */
|
|
58
58
|
const NAME_ONLY = "--name-only";
|
|
59
|
+
/**
|
|
60
|
+
* Suppress rename detection when discovering changed files.
|
|
61
|
+
*
|
|
62
|
+
* With it on, `git diff --name-only` reports a rename as the destination path
|
|
63
|
+
* only. Moving a watched threshold file to an unwatched path therefore lists
|
|
64
|
+
* one name the ratchet does not watch, and the loosening at the old path is
|
|
65
|
+
* never compared. Both sides have to be visible for the gate to mean anything.
|
|
66
|
+
*/
|
|
67
|
+
const NO_RENAMES = "--no-renames";
|
|
59
68
|
|
|
60
69
|
/**
|
|
61
70
|
* Run git, returning stdout or null on any failure.
|
|
@@ -87,7 +96,7 @@ function git(args, cwd) {
|
|
|
87
96
|
*/
|
|
88
97
|
function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
89
98
|
if (mode === "staged") {
|
|
90
|
-
const diff = git(["diff", "--cached", NAME_ONLY], root);
|
|
99
|
+
const diff = git(["diff", "--cached", NAME_ONLY, NO_RENAMES], root);
|
|
91
100
|
if (diff === null) return null;
|
|
92
101
|
return {
|
|
93
102
|
files: diff.split("\n").filter(Boolean),
|
|
@@ -99,7 +108,7 @@ function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
|
99
108
|
if (!baseRef) return null;
|
|
100
109
|
const mergeBase = git(["merge-base", baseRef, "HEAD"], root)?.trim();
|
|
101
110
|
if (!mergeBase) return null;
|
|
102
|
-
const diff = git(["diff", NAME_ONLY, mergeBase, "HEAD"], root);
|
|
111
|
+
const diff = git(["diff", NAME_ONLY, NO_RENAMES, mergeBase, "HEAD"], root);
|
|
103
112
|
if (diff === null) return null;
|
|
104
113
|
return {
|
|
105
114
|
files: diff.split("\n").filter(Boolean),
|
|
@@ -107,7 +116,7 @@ function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
|
107
116
|
readCurrent: f => git(["show", `HEAD:${f}`], root),
|
|
108
117
|
};
|
|
109
118
|
}
|
|
110
|
-
const diff = git(["diff", NAME_ONLY, "HEAD"], root);
|
|
119
|
+
const diff = git(["diff", NAME_ONLY, NO_RENAMES, "HEAD"], root);
|
|
111
120
|
if (diff === null) return null;
|
|
112
121
|
return {
|
|
113
122
|
files: onlyFiles ?? diff.split("\n").filter(Boolean),
|
|
@@ -122,6 +131,31 @@ function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
|
122
131
|
};
|
|
123
132
|
}
|
|
124
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Decide the exit code when the ratchet cannot determine what changed.
|
|
136
|
+
*
|
|
137
|
+
* `staged` and `base` are enforcement gates — pre-commit and CI. A gate that
|
|
138
|
+
* cannot see the change set has not found the change set clean, and returning 0
|
|
139
|
+
* reports exactly that. It fails closed, loudly.
|
|
140
|
+
*
|
|
141
|
+
* `hook` is advisory feedback to an agent mid-edit, fires on every tool call,
|
|
142
|
+
* and blocks nothing downstream. Failing it closed on a transient git hiccup
|
|
143
|
+
* would turn a hint into an outage, so it stays permissive — but still says so.
|
|
144
|
+
* @param {"hook"|"staged"|"base"} mode Comparison mode
|
|
145
|
+
* @param {string} reason What could not be determined
|
|
146
|
+
* @returns {number} Process exit code
|
|
147
|
+
*/
|
|
148
|
+
function undeterminable(mode, reason) {
|
|
149
|
+
process.stderr.write(
|
|
150
|
+
`threshold-ratchet: ${reason}; the ratchet could not run in ${mode} mode\n`
|
|
151
|
+
);
|
|
152
|
+
if (mode === "hook") return 0;
|
|
153
|
+
process.stderr.write(
|
|
154
|
+
"threshold-ratchet: failing closed — an enforcement gate that cannot read the change set has not verified it\n"
|
|
155
|
+
);
|
|
156
|
+
return 1;
|
|
157
|
+
}
|
|
158
|
+
|
|
125
159
|
/**
|
|
126
160
|
* Run the ratchet for a mode, print the report, and return the exit code.
|
|
127
161
|
* @param {"hook"|"staged"|"base"} mode Comparison mode
|
|
@@ -131,9 +165,9 @@ function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
|
131
165
|
*/
|
|
132
166
|
function run(mode, baseRef, onlyFiles) {
|
|
133
167
|
const root = git(["rev-parse", "--show-toplevel"])?.trim();
|
|
134
|
-
if (!root) return
|
|
168
|
+
if (!root) return undeterminable(mode, "not a git repository");
|
|
135
169
|
const plan = resolvePlan(mode, root, baseRef, onlyFiles);
|
|
136
|
-
if (!plan) return
|
|
170
|
+
if (!plan) return undeterminable(mode, "could not resolve the changed files");
|
|
137
171
|
|
|
138
172
|
const watched = plan.files.filter(f => familyFor(f));
|
|
139
173
|
if (watched.length === 0) return 0;
|
|
@@ -56,6 +56,15 @@ const GIT = GIT_LOCATIONS.find(candidate => fs.existsSync(candidate)) ?? "git";
|
|
|
56
56
|
|
|
57
57
|
/** Git flag shared by every changed-file listing. */
|
|
58
58
|
const NAME_ONLY = "--name-only";
|
|
59
|
+
/**
|
|
60
|
+
* Suppress rename detection when discovering changed files.
|
|
61
|
+
*
|
|
62
|
+
* With it on, `git diff --name-only` reports a rename as the destination path
|
|
63
|
+
* only. Moving a watched threshold file to an unwatched path therefore lists
|
|
64
|
+
* one name the ratchet does not watch, and the loosening at the old path is
|
|
65
|
+
* never compared. Both sides have to be visible for the gate to mean anything.
|
|
66
|
+
*/
|
|
67
|
+
const NO_RENAMES = "--no-renames";
|
|
59
68
|
|
|
60
69
|
/**
|
|
61
70
|
* Run git, returning stdout or null on any failure.
|
|
@@ -87,7 +96,7 @@ function git(args, cwd) {
|
|
|
87
96
|
*/
|
|
88
97
|
function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
89
98
|
if (mode === "staged") {
|
|
90
|
-
const diff = git(["diff", "--cached", NAME_ONLY], root);
|
|
99
|
+
const diff = git(["diff", "--cached", NAME_ONLY, NO_RENAMES], root);
|
|
91
100
|
if (diff === null) return null;
|
|
92
101
|
return {
|
|
93
102
|
files: diff.split("\n").filter(Boolean),
|
|
@@ -99,7 +108,7 @@ function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
|
99
108
|
if (!baseRef) return null;
|
|
100
109
|
const mergeBase = git(["merge-base", baseRef, "HEAD"], root)?.trim();
|
|
101
110
|
if (!mergeBase) return null;
|
|
102
|
-
const diff = git(["diff", NAME_ONLY, mergeBase, "HEAD"], root);
|
|
111
|
+
const diff = git(["diff", NAME_ONLY, NO_RENAMES, mergeBase, "HEAD"], root);
|
|
103
112
|
if (diff === null) return null;
|
|
104
113
|
return {
|
|
105
114
|
files: diff.split("\n").filter(Boolean),
|
|
@@ -107,7 +116,7 @@ function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
|
107
116
|
readCurrent: f => git(["show", `HEAD:${f}`], root),
|
|
108
117
|
};
|
|
109
118
|
}
|
|
110
|
-
const diff = git(["diff", NAME_ONLY, "HEAD"], root);
|
|
119
|
+
const diff = git(["diff", NAME_ONLY, NO_RENAMES, "HEAD"], root);
|
|
111
120
|
if (diff === null) return null;
|
|
112
121
|
return {
|
|
113
122
|
files: onlyFiles ?? diff.split("\n").filter(Boolean),
|
|
@@ -122,6 +131,31 @@ function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
|
122
131
|
};
|
|
123
132
|
}
|
|
124
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Decide the exit code when the ratchet cannot determine what changed.
|
|
136
|
+
*
|
|
137
|
+
* `staged` and `base` are enforcement gates — pre-commit and CI. A gate that
|
|
138
|
+
* cannot see the change set has not found the change set clean, and returning 0
|
|
139
|
+
* reports exactly that. It fails closed, loudly.
|
|
140
|
+
*
|
|
141
|
+
* `hook` is advisory feedback to an agent mid-edit, fires on every tool call,
|
|
142
|
+
* and blocks nothing downstream. Failing it closed on a transient git hiccup
|
|
143
|
+
* would turn a hint into an outage, so it stays permissive — but still says so.
|
|
144
|
+
* @param {"hook"|"staged"|"base"} mode Comparison mode
|
|
145
|
+
* @param {string} reason What could not be determined
|
|
146
|
+
* @returns {number} Process exit code
|
|
147
|
+
*/
|
|
148
|
+
function undeterminable(mode, reason) {
|
|
149
|
+
process.stderr.write(
|
|
150
|
+
`threshold-ratchet: ${reason}; the ratchet could not run in ${mode} mode\n`
|
|
151
|
+
);
|
|
152
|
+
if (mode === "hook") return 0;
|
|
153
|
+
process.stderr.write(
|
|
154
|
+
"threshold-ratchet: failing closed — an enforcement gate that cannot read the change set has not verified it\n"
|
|
155
|
+
);
|
|
156
|
+
return 1;
|
|
157
|
+
}
|
|
158
|
+
|
|
125
159
|
/**
|
|
126
160
|
* Run the ratchet for a mode, print the report, and return the exit code.
|
|
127
161
|
* @param {"hook"|"staged"|"base"} mode Comparison mode
|
|
@@ -131,9 +165,9 @@ function resolvePlan(mode, root, baseRef, onlyFiles) {
|
|
|
131
165
|
*/
|
|
132
166
|
function run(mode, baseRef, onlyFiles) {
|
|
133
167
|
const root = git(["rev-parse", "--show-toplevel"])?.trim();
|
|
134
|
-
if (!root) return
|
|
168
|
+
if (!root) return undeterminable(mode, "not a git repository");
|
|
135
169
|
const plan = resolvePlan(mode, root, baseRef, onlyFiles);
|
|
136
|
-
if (!plan) return
|
|
170
|
+
if (!plan) return undeterminable(mode, "could not resolve the changed files");
|
|
137
171
|
|
|
138
172
|
const watched = plan.files.filter(f => familyFor(f));
|
|
139
173
|
if (watched.length === 0) return 0;
|