@codyswann/lisa 2.325.4 → 2.325.5
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/dist/core/upstream-evidence-manifest.js +1 -1
- 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-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-cursor/.claude-plugin/plugin.json +1 -1
- 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/scripts/check-security-floors.mjs +98 -13
|
@@ -961,7 +961,7 @@ export const UPSTREAM_EVIDENCE_MANIFEST = Object.freeze({
|
|
|
961
961
|
"scripts/check-learnings-budget.ts": "007430c2d6938efcc79ccbfd5717ebe2c7cf66b4de9a21a3e67b8db7f3600349",
|
|
962
962
|
"scripts/check-plugins-sync.sh": "3a99cbff0e8ec5e7c944690eae003a6d51b51c85436d77bd37faea4d553728af",
|
|
963
963
|
"scripts/check-rules-pairing.sh": "4d4a0d9e8d36794a22020f419c879d7336b1c5bfe883acdcc826d26764560c7a",
|
|
964
|
-
"scripts/check-security-floors.mjs": "
|
|
964
|
+
"scripts/check-security-floors.mjs": "0060a0f65885b54fc93bd3885ca249cbb1ac822c52813817aae640bc1303827b",
|
|
965
965
|
"scripts/claude-remote-setup.sh": "0e33accf8aa057c70497f01c38bef9f9f3801d649272f583578d89201b242655",
|
|
966
966
|
"scripts/clean-dist.mjs": "04970d768464acbf96ebeb77c16a6a3b3da56c744eef0da64c573c6152ee0dc7",
|
|
967
967
|
"scripts/cleanup-amplify-branches.sh": "eb9db90b07818dd156dd48d04b6350a10b39be8ffe0267d72cc13705c8eb5350",
|
package/package.json
CHANGED
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"brace-expansion": ">=5.0.9"
|
|
116
116
|
},
|
|
117
117
|
"name": "@codyswann/lisa",
|
|
118
|
-
"version": "2.325.
|
|
118
|
+
"version": "2.325.5",
|
|
119
119
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
120
120
|
"main": "dist/index.js",
|
|
121
121
|
"exports": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.325.
|
|
3
|
+
"version": "2.325.5",
|
|
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": "2.325.
|
|
3
|
+
"version": "2.325.5",
|
|
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": "2.325.
|
|
3
|
+
"version": "2.325.5",
|
|
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": "2.325.
|
|
3
|
+
"version": "2.325.5",
|
|
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": "2.325.
|
|
3
|
+
"version": "2.325.5",
|
|
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"
|
|
@@ -43,12 +43,45 @@ const GATING_SEVERITIES = new Set(["high", "critical"]);
|
|
|
43
43
|
|
|
44
44
|
const ADVISORY_ENDPOINT = "https://api.github.com/advisories";
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Resolve a `$name` self-reference to the range the manifest pins it to.
|
|
48
|
+
*
|
|
49
|
+
* Searches the dependency sections of every governance group, because a
|
|
50
|
+
* template may declare the target in `force`, `defaults` or `merge` and the
|
|
51
|
+
* reference means the same thing in each. Constraint sections that are
|
|
52
|
+
* themselves override maps are skipped, so a `$name` cannot resolve to another
|
|
53
|
+
* `$name` and loop.
|
|
54
|
+
* @param {object} manifest A parsed package.lisa.json.
|
|
55
|
+
* @param {string} name The referenced package.
|
|
56
|
+
* @returns {string|null} The pinned range, or null when nothing declares it.
|
|
57
|
+
*/
|
|
58
|
+
export function resolveSelfReference(manifest, name) {
|
|
59
|
+
const DEPENDENCY_SECTIONS = [
|
|
60
|
+
"dependencies",
|
|
61
|
+
"devDependencies",
|
|
62
|
+
"peerDependencies",
|
|
63
|
+
];
|
|
64
|
+
for (const group of GOVERNANCE_GROUPS) {
|
|
65
|
+
const block = manifest[group];
|
|
66
|
+
if (!block || typeof block !== "object") continue;
|
|
67
|
+
for (const section of DEPENDENCY_SECTIONS) {
|
|
68
|
+
const spec = block[section]?.[name];
|
|
69
|
+
if (typeof spec === "string" && !spec.startsWith("$")) return spec;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
46
75
|
/**
|
|
47
76
|
* Every version constraint declared across the template manifests.
|
|
48
|
-
* @returns {Map<string, Array<{file: string, path: string, spec: string}
|
|
77
|
+
* @returns {{found: Map<string, Array<{file: string, path: string, spec: string}>>,
|
|
78
|
+
* unresolved: Array<{file: string, path: string, name: string, spec: string}>}}
|
|
79
|
+
* Constraints by package name, plus self-references pointing at nothing.
|
|
49
80
|
*/
|
|
50
81
|
function collectFloors() {
|
|
51
82
|
const found = new Map();
|
|
83
|
+
/** `$name` references pointing at nothing this manifest declares. */
|
|
84
|
+
const unresolved = [];
|
|
52
85
|
const files = globSync("*/package-lisa/package.lisa.json").filter(
|
|
53
86
|
file => !file.includes("node_modules") && !file.includes(".worktrees")
|
|
54
87
|
);
|
|
@@ -66,17 +99,45 @@ function collectFloors() {
|
|
|
66
99
|
const entries = block[section];
|
|
67
100
|
if (!entries || typeof entries !== "object") continue;
|
|
68
101
|
for (const [name, spec] of Object.entries(entries)) {
|
|
69
|
-
|
|
70
|
-
// no floor of
|
|
71
|
-
|
|
72
|
-
|
|
102
|
+
if (typeof spec !== "string") continue;
|
|
103
|
+
// A `$name` self-reference carries no floor of its own — it adopts
|
|
104
|
+
// whatever the manifest pins that package to elsewhere. Resolve it
|
|
105
|
+
// and check THAT, rather than skipping.
|
|
106
|
+
//
|
|
107
|
+
// Skipping was safe only by coincidence: every `$name` in the
|
|
108
|
+
// templates today happens to target a package also declared as a
|
|
109
|
+
// literal in a scanned group, so the range got checked under its own
|
|
110
|
+
// entry. Nothing enforces that. The first `$name` whose target is
|
|
111
|
+
// declared only downstream — or not at all — would be a floor
|
|
112
|
+
// nothing checks, reported as clean, which is worse than no check.
|
|
113
|
+
if (spec.startsWith("$")) {
|
|
114
|
+
const target = resolveSelfReference(manifest, spec.slice(1));
|
|
115
|
+
if (target === null) {
|
|
116
|
+
unresolved.push({
|
|
117
|
+
file,
|
|
118
|
+
path: `${group}.${section}`,
|
|
119
|
+
name,
|
|
120
|
+
spec,
|
|
121
|
+
});
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (!/\d/.test(target)) continue;
|
|
125
|
+
if (!found.has(name)) found.set(name, []);
|
|
126
|
+
found
|
|
127
|
+
.get(name)
|
|
128
|
+
.push({ file, path: `${group}.${section}`, spec: target });
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
// A literal carrying no digits — "workspace:*", "latest" — is not a
|
|
132
|
+
// floor and there is nothing to compare.
|
|
133
|
+
if (!/\d/.test(spec)) continue;
|
|
73
134
|
if (!found.has(name)) found.set(name, []);
|
|
74
135
|
found.get(name).push({ file, path: `${group}.${section}`, spec });
|
|
75
136
|
}
|
|
76
137
|
}
|
|
77
138
|
}
|
|
78
139
|
}
|
|
79
|
-
return found;
|
|
140
|
+
return { found, unresolved };
|
|
80
141
|
}
|
|
81
142
|
|
|
82
143
|
/**
|
|
@@ -185,10 +246,10 @@ async function advisoriesFor(name) {
|
|
|
185
246
|
|
|
186
247
|
/**
|
|
187
248
|
* Audit every collected floor.
|
|
188
|
-
* @returns {Promise<{problems: Array, unreachable:
|
|
249
|
+
* @returns {Promise<{problems: Array, unreachable: Array, unresolved: Array, checked: number}>} Findings.
|
|
189
250
|
*/
|
|
190
251
|
async function audit() {
|
|
191
|
-
const floors = collectFloors();
|
|
252
|
+
const { found: floors, unresolved } = collectFloors();
|
|
192
253
|
const problems = [];
|
|
193
254
|
const unreachable = [];
|
|
194
255
|
for (const [name, sites] of floors) {
|
|
@@ -220,16 +281,18 @@ async function audit() {
|
|
|
220
281
|
}
|
|
221
282
|
}
|
|
222
283
|
}
|
|
223
|
-
return { problems, unreachable, checked: floors.size };
|
|
284
|
+
return { problems, unreachable, unresolved, checked: floors.size };
|
|
224
285
|
}
|
|
225
286
|
|
|
226
287
|
async function main() {
|
|
227
288
|
const strict = process.argv.includes("--strict");
|
|
228
289
|
const asJson = process.argv.includes("--json");
|
|
229
|
-
const { problems, unreachable, checked } = await audit();
|
|
290
|
+
const { problems, unreachable, unresolved, checked } = await audit();
|
|
230
291
|
|
|
231
292
|
if (asJson) {
|
|
232
|
-
console.log(
|
|
293
|
+
console.log(
|
|
294
|
+
JSON.stringify({ problems, unreachable, unresolved, checked }, null, 2)
|
|
295
|
+
);
|
|
233
296
|
} else if (problems.length === 0) {
|
|
234
297
|
console.log(
|
|
235
298
|
`## Security floors\n\nNo force-pinned floor permits a high or critical vulnerable release. ${checked} package(s) checked.`
|
|
@@ -251,7 +314,24 @@ async function main() {
|
|
|
251
314
|
);
|
|
252
315
|
}
|
|
253
316
|
|
|
254
|
-
|
|
317
|
+
// Markdown notes belong to the human report only. Printed in --json mode
|
|
318
|
+
// they follow the document and break every parser reading it; the same
|
|
319
|
+
// facts are already fields in the JSON.
|
|
320
|
+
if (!asJson && unresolved.length > 0) {
|
|
321
|
+
console.log(
|
|
322
|
+
`\n> **${unresolved.length} self-reference(s) resolve to nothing.** A \`$name\` adopts whatever the manifest pins that package to; when nothing pins it, there is no floor to check and no floor to enforce. Reported rather than skipped, because silence here is indistinguishable from a clean result.`
|
|
323
|
+
);
|
|
324
|
+
for (const entry of unresolved) {
|
|
325
|
+
console.log(
|
|
326
|
+
`> - \`${entry.name}: ${entry.spec}\` in ${entry.file} ${entry.path}`
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
console.log(
|
|
330
|
+
"> Fix by declaring the target in a governance dependency section, or by replacing the reference with an explicit floor."
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (!asJson && unreachable.length > 0) {
|
|
255
335
|
const limited = unreachable.filter(entry =>
|
|
256
336
|
entry.reason.includes("rate limited")
|
|
257
337
|
);
|
|
@@ -275,7 +355,12 @@ async function main() {
|
|
|
275
355
|
// Under --strict an inconclusive run also fails: it proves nothing, and
|
|
276
356
|
// treating "could not check" as "checked and clean" is exactly the silent
|
|
277
357
|
// degradation this script exists to prevent.
|
|
278
|
-
|
|
358
|
+
// An unresolved self-reference gates for the same reason an inconclusive one
|
|
359
|
+
// does: it is a floor nobody checked, and letting it pass reports it clean.
|
|
360
|
+
if (
|
|
361
|
+
strict &&
|
|
362
|
+
(problems.length > 0 || unreachable.length > 0 || unresolved.length > 0)
|
|
363
|
+
) {
|
|
279
364
|
process.exitCode = 1;
|
|
280
365
|
}
|
|
281
366
|
}
|