@codyswann/lisa 4.27.5 → 4.27.7
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-enforcement-fallback.sh +27 -4
- package/all/copy-overwrite/scripts/lisa-hooks/block-direct-issue-create.sh +507 -11
- package/dist/cli/doctor-enforcement-coverage.d.ts +14 -0
- package/dist/cli/doctor-enforcement-coverage.d.ts.map +1 -0
- package/dist/cli/doctor-enforcement-coverage.js +103 -0
- package/dist/cli/doctor-enforcement-coverage.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +9 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/core/enforcement-census-report.d.ts +19 -0
- package/dist/core/enforcement-census-report.d.ts.map +1 -0
- package/dist/core/enforcement-census-report.js +198 -0
- package/dist/core/enforcement-census-report.js.map +1 -0
- package/dist/core/enforcement-census.d.ts +177 -0
- package/dist/core/enforcement-census.d.ts.map +1 -0
- package/dist/core/enforcement-census.js +252 -0
- package/dist/core/enforcement-census.js.map +1 -0
- package/dist/core/enforcement-coverage.d.ts +168 -0
- package/dist/core/enforcement-coverage.d.ts.map +1 -0
- package/dist/core/enforcement-coverage.js +342 -0
- package/dist/core/enforcement-coverage.js.map +1 -0
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +8 -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 +21 -5
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/lisa-block-direct-issue-create.ts +180 -19
- package/package.json +4 -3
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-setup-automations/SKILL.md +23 -0
- package/plugins/lisa/hooks/block-direct-issue-create.sh +507 -11
- package/plugins/lisa/skills/lisa-setup-automations/SKILL.md +23 -0
- package/plugins/lisa-agy/hooks/block-direct-issue-create.sh +507 -11
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/skills/lisa-setup-automations/SKILL.md +23 -0
- 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/block-direct-issue-create.sh +507 -11
- package/plugins/lisa-copilot/skills/lisa-setup-automations/SKILL.md +23 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/block-direct-issue-create.sh +507 -11
- package/plugins/lisa-cursor/skills/lisa-setup-automations/SKILL.md +23 -0
- 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/block-direct-issue-create.sh +507 -11
- package/plugins/src/base/skills/lisa-setup-automations/SKILL.md +23 -0
- package/scripts/lisa-enforcement-census.mjs +168 -0
- package/scripts/lisa-enforcement-fallback.sh +27 -4
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Fleet enforcement census — re-measures how many host checkouts resolve a
|
|
4
|
+
* Lisa enforcement guard, and reports it.
|
|
5
|
+
*
|
|
6
|
+
* The per-session staleness notice in `scripts/lisa-enforcement-fallback.sh`
|
|
7
|
+
* tells THIS session about THIS checkout, which is right and is not the gap.
|
|
8
|
+
* The gap is that nobody was looking at the fleet, so the only fleet-wide
|
|
9
|
+
* number that ever existed was taken by hand and frozen in a comment
|
|
10
|
+
* (CodySwannGT/lisa#3490). This runs the measurement again, every time.
|
|
11
|
+
*
|
|
12
|
+
* Two properties it must keep:
|
|
13
|
+
*
|
|
14
|
+
* - It REPORTS. Its exit status is 0 for every finding about the fleet,
|
|
15
|
+
* including a fleet where every checkout is stale. A census that could
|
|
16
|
+
* redden someone's build would be routed around.
|
|
17
|
+
* - It keeps "resolves nothing" apart from "resolves something old". They are
|
|
18
|
+
* different failures with different remedies, and folding them loses the
|
|
19
|
+
* serious half.
|
|
20
|
+
*
|
|
21
|
+
* Usage:
|
|
22
|
+
* node scripts/lisa-enforcement-census.mjs [options]
|
|
23
|
+
*
|
|
24
|
+
* Options:
|
|
25
|
+
* --roster <path> Roster file (default: .lisa.workspaces.json beside this repo)
|
|
26
|
+
* --scan <dir> Also discover checkouts under <dir>. Repeatable.
|
|
27
|
+
* --depth <n> How deep --scan descends (default 2)
|
|
28
|
+
* --reference <ver> Compare against this version instead of the newest found
|
|
29
|
+
* --redact Replace real paths with stable anonymous labels
|
|
30
|
+
* --json Emit the measured fleet as JSON
|
|
31
|
+
*
|
|
32
|
+
* Exit status: 0 for every fleet finding. 1 only when an explicitly named
|
|
33
|
+
* roster cannot be read, and 2 for a usage error — both are failures of the
|
|
34
|
+
* census's own inputs, never findings about the fleet.
|
|
35
|
+
*/
|
|
36
|
+
import path from "node:path";
|
|
37
|
+
import { fileURLToPath } from "node:url";
|
|
38
|
+
|
|
39
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
40
|
+
const repoRoot = path.resolve(here, "..");
|
|
41
|
+
|
|
42
|
+
const census = await import(
|
|
43
|
+
path.join(repoRoot, "dist", "core", "enforcement-census.js")
|
|
44
|
+
).catch(error => {
|
|
45
|
+
process.stderr.write(
|
|
46
|
+
`Could not load the census from dist/. Run \`bun run build:dist\` first.\n${error.message}\n`
|
|
47
|
+
);
|
|
48
|
+
process.exit(2);
|
|
49
|
+
});
|
|
50
|
+
const report = await import(
|
|
51
|
+
path.join(repoRoot, "dist", "core", "enforcement-census-report.js")
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const options = {
|
|
55
|
+
roster: null,
|
|
56
|
+
scans: [],
|
|
57
|
+
depth: 2,
|
|
58
|
+
reference: null,
|
|
59
|
+
redact: false,
|
|
60
|
+
json: false,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const argv = process.argv.slice(2);
|
|
64
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
65
|
+
const flag = argv[index];
|
|
66
|
+
const value = argv[index + 1];
|
|
67
|
+
// A value-taking flag left at the end of the line has no value. Assigning
|
|
68
|
+
// `undefined` there silently falls back to the default roster or drops the
|
|
69
|
+
// requested setting, so the run measures something other than what was
|
|
70
|
+
// asked for and says nothing about it — a census reporting the wrong fleet
|
|
71
|
+
// is worse than one that refuses. This is the census's own input being
|
|
72
|
+
// wrong, so it exits 2 like any other usage error and never as a finding.
|
|
73
|
+
const VALUE_FLAGS = ["--roster", "--scan", "--depth", "--reference"];
|
|
74
|
+
if (VALUE_FLAGS.includes(flag) && value === undefined) {
|
|
75
|
+
process.stderr.write(`${flag} requires a value\n`);
|
|
76
|
+
process.exit(2);
|
|
77
|
+
}
|
|
78
|
+
if (flag === "--roster") {
|
|
79
|
+
options.roster = value;
|
|
80
|
+
index += 1;
|
|
81
|
+
} else if (flag === "--scan") {
|
|
82
|
+
options.scans.push(value);
|
|
83
|
+
index += 1;
|
|
84
|
+
} else if (flag === "--depth") {
|
|
85
|
+
options.depth = Number.parseInt(value ?? "", 10);
|
|
86
|
+
index += 1;
|
|
87
|
+
} else if (flag === "--reference") {
|
|
88
|
+
options.reference = value;
|
|
89
|
+
index += 1;
|
|
90
|
+
} else if (flag === "--redact") {
|
|
91
|
+
options.redact = true;
|
|
92
|
+
} else if (flag === "--json") {
|
|
93
|
+
options.json = true;
|
|
94
|
+
} else if (flag === "--help" || flag === "-h") {
|
|
95
|
+
process.stdout.write(
|
|
96
|
+
"Usage: node scripts/lisa-enforcement-census.mjs [--roster <path>] [--scan <dir>] [--depth <n>] [--reference <ver>] [--redact] [--json]\n"
|
|
97
|
+
);
|
|
98
|
+
process.exit(0);
|
|
99
|
+
} else {
|
|
100
|
+
process.stderr.write(`Unknown option: ${flag}\n`);
|
|
101
|
+
process.exit(2);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!Number.isInteger(options.depth) || options.depth < 0) {
|
|
106
|
+
process.stderr.write("--depth must be a non-negative integer\n");
|
|
107
|
+
process.exit(2);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const rosterPath =
|
|
111
|
+
options.roster ?? path.join(repoRoot, census.DEFAULT_ROSTER_FILE);
|
|
112
|
+
const rosterEntries = await census.readFleetRoster(rosterPath);
|
|
113
|
+
|
|
114
|
+
// An explicitly named roster that cannot be read is an input error, not a
|
|
115
|
+
// finding: the operator asked for a specific file and did not get it. A missing
|
|
116
|
+
// DEFAULT roster is neither — this repository is simply not a fleet hub — so it
|
|
117
|
+
// reports an empty fleet and still exits 0.
|
|
118
|
+
if (rosterEntries === null && options.roster !== null) {
|
|
119
|
+
process.stderr.write(`Could not read the roster: ${rosterPath}\n`);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const scanned = (
|
|
124
|
+
await Promise.all(
|
|
125
|
+
options.scans.map(directory =>
|
|
126
|
+
census.scanForCheckouts(directory, options.depth)
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
).flat();
|
|
130
|
+
|
|
131
|
+
const roster = await census.dedupeRoster([
|
|
132
|
+
...(rosterEntries ?? []),
|
|
133
|
+
...scanned,
|
|
134
|
+
]);
|
|
135
|
+
|
|
136
|
+
const origins = [
|
|
137
|
+
rosterEntries === null ? null : rosterPath,
|
|
138
|
+
...options.scans.map(directory => `scan of ${directory}`),
|
|
139
|
+
].filter(Boolean);
|
|
140
|
+
|
|
141
|
+
const seedVersion = await import(path.join(repoRoot, "package.json"), {
|
|
142
|
+
with: { type: "json" },
|
|
143
|
+
})
|
|
144
|
+
.then(module => module.default.version ?? null)
|
|
145
|
+
.catch(() => null);
|
|
146
|
+
|
|
147
|
+
const measured = await census.runFleetCensus({
|
|
148
|
+
roster,
|
|
149
|
+
rosterOrigin: origins.length === 0 ? "no roster found" : origins.join(" + "),
|
|
150
|
+
seedVersion,
|
|
151
|
+
reference: options.reference,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const output = options.redact ? report.redactCensus(measured) : measured;
|
|
155
|
+
|
|
156
|
+
process.stdout.write(
|
|
157
|
+
options.json
|
|
158
|
+
? `${JSON.stringify(output, null, 2)}\n`
|
|
159
|
+
: report.renderFleetCensusReport(output)
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// Unconditional. Nothing above may change it.
|
|
163
|
+
//
|
|
164
|
+
// Set rather than called: `process.exit()` tears the process down synchronously
|
|
165
|
+
// and can drop a pending `process.stdout.write` when stdout is a pipe, which is
|
|
166
|
+
// exactly how this is read — piped to a pager, a file, or a scheduled loop's
|
|
167
|
+
// log. A truncated census reports a smaller fleet than it measured, silently.
|
|
168
|
+
process.exitCode = 0;
|
|
@@ -404,10 +404,33 @@ fi
|
|
|
404
404
|
# - `main` cut 80 releases in 24 hours, median gap 10 minutes. "Behind the
|
|
405
405
|
# newest Lisa on this disk" is the DEFAULT state of a checkout within
|
|
406
406
|
# minutes of being cut, through nothing anyone did wrong.
|
|
407
|
-
# -
|
|
408
|
-
#
|
|
409
|
-
#
|
|
410
|
-
#
|
|
407
|
+
# - Measured once across the host checkouts on one fleet: of those that
|
|
408
|
+
# resolved guards at all, every one was behind or undateable and none was
|
|
409
|
+
# current, several by a whole MAJOR — while a larger number resolved NO
|
|
410
|
+
# guard at all.
|
|
411
|
+
#
|
|
412
|
+
# That second reading used to be written here as a set of counts, and that was
|
|
413
|
+
# the wrong place for it. A number in a comment is a measurement, not a monitor:
|
|
414
|
+
# it was true on the day it was taken and nothing re-took it, so the drift after
|
|
415
|
+
# that date was unobserved — which is the same defect the number documents. The
|
|
416
|
+
# counts are therefore not restated here. Re-derive them:
|
|
417
|
+
#
|
|
418
|
+
# Run these FROM A LISA MONOREPO CHECKOUT — the census and the fleet roster are
|
|
419
|
+
# Lisa-monorepo artifacts, and this comment travels into host projects where
|
|
420
|
+
# neither exists. The script wrapper builds `dist/` first, which a fresh clone
|
|
421
|
+
# does not have:
|
|
422
|
+
#
|
|
423
|
+
# bun run lisa:enforcement-census # roster on this machine
|
|
424
|
+
# bun run lisa:enforcement-census -- --redact # safe to quote publicly
|
|
425
|
+
#
|
|
426
|
+
# In a host project the local half of the same question is `lisa doctor`, which
|
|
427
|
+
# reports what THIS checkout resolves and needs no roster.
|
|
428
|
+
#
|
|
429
|
+
# The census reports and never gates, and it keeps "resolves NO guard" apart
|
|
430
|
+
# from "resolves something old" — different failures, different remedies, and
|
|
431
|
+
# folding them is what made the unenforced checkouts easy to miss
|
|
432
|
+
# (CodySwannGT/lisa#3490). `lisa doctor` carries the same finding for the single
|
|
433
|
+
# checkout it is run in.
|
|
411
434
|
#
|
|
412
435
|
# So no distance threshold rescues it — even the strictest version predicate is
|
|
413
436
|
# permanently true across the fleet. The noise is the REPETITION, not the
|