@codyswann/lisa 4.27.5 → 4.27.6

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 (86) hide show
  1. package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +27 -4
  2. package/dist/cli/doctor-enforcement-coverage.d.ts +14 -0
  3. package/dist/cli/doctor-enforcement-coverage.d.ts.map +1 -0
  4. package/dist/cli/doctor-enforcement-coverage.js +103 -0
  5. package/dist/cli/doctor-enforcement-coverage.js.map +1 -0
  6. package/dist/cli/doctor.d.ts.map +1 -1
  7. package/dist/cli/doctor.js +9 -0
  8. package/dist/cli/doctor.js.map +1 -1
  9. package/dist/core/enforcement-census-report.d.ts +19 -0
  10. package/dist/core/enforcement-census-report.d.ts.map +1 -0
  11. package/dist/core/enforcement-census-report.js +198 -0
  12. package/dist/core/enforcement-census-report.js.map +1 -0
  13. package/dist/core/enforcement-census.d.ts +177 -0
  14. package/dist/core/enforcement-census.d.ts.map +1 -0
  15. package/dist/core/enforcement-census.js +252 -0
  16. package/dist/core/enforcement-census.js.map +1 -0
  17. package/dist/core/enforcement-coverage.d.ts +168 -0
  18. package/dist/core/enforcement-coverage.d.ts.map +1 -0
  19. package/dist/core/enforcement-coverage.js +342 -0
  20. package/dist/core/enforcement-coverage.js.map +1 -0
  21. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  22. package/dist/core/lisa-owned-hash-ledger.js +4 -0
  23. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  24. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  25. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  26. package/dist/core/upstream-evidence-manifest.js +17 -3
  27. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  28. package/package.json +4 -3
  29. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  31. package/plugins/lisa/.codex-plugin/skills/lisa-setup-automations/SKILL.md +23 -0
  32. package/plugins/lisa/skills/lisa-setup-automations/SKILL.md +23 -0
  33. package/plugins/lisa-agy/plugin.json +1 -1
  34. package/plugins/lisa-agy/skills/lisa-setup-automations/SKILL.md +23 -0
  35. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  38. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  40. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-copilot/skills/lisa-setup-automations/SKILL.md +23 -0
  42. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-cursor/skills/lisa-setup-automations/SKILL.md +23 -0
  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-agy/plugin.json +1 -1
  72. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  76. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  77. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  81. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  82. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  84. package/plugins/src/base/skills/lisa-setup-automations/SKILL.md +23 -0
  85. package/scripts/lisa-enforcement-census.mjs +168 -0
  86. package/scripts/lisa-enforcement-fallback.sh +27 -4
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.27.5",
3
+ "version": "4.27.6",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.27.5",
3
+ "version": "4.27.6",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -207,6 +207,29 @@ project: the per-check marker dedupe converges under a single scheduled runner,
207
207
  and two concurrent runs can both observe an empty open-ticket set and both
208
208
  file. Tear-down removes it with the rest of the `lisa-auto-<project>-*` set.
209
209
 
210
+ **Optional automation — the fleet enforcement census.** Register
211
+ `lisa-auto-<project>-enforcement-census` running `/lisa:enforcement-census`
212
+ once a **day** only when BOTH are true of the repository being set up: it
213
+ maintains a fleet roster (`.lisa.workspaces.json`, the machine-local list of
214
+ host checkouts), and it provides the `/lisa:enforcement-census` command. Both
215
+ hold in the Lisa monorepo and in no ordinary host project, which is the point —
216
+ the census measures OTHER checkouts on the same machine, so only the workstation
217
+ holding the roster has a fleet to measure. Where either is absent, register
218
+ nothing — a host project has no fleet, and scheduling a command it does not
219
+ have would be a loop that fails every night — and report the census as SKIPPED
220
+ naming which prerequisite was missing, per the report contract. Registering
221
+ nothing is correct; omitting it from the report is not, because a silently
222
+ absent loop is indistinguishable from one that was never asked for.
223
+
224
+ It **reports and never gates**: no finding about the fleet changes an exit
225
+ status, and no run files a ticket. Enforcement resolves from the checkout an
226
+ agent is working in, so a checkout resolving no guard is protected by nothing
227
+ while looking identical, from inside a session, to one protected by an old
228
+ policy — and nothing was re-measuring that (CodySwannGT/lisa#3490). The
229
+ per-checkout half of the same finding is carried by `lisa doctor`, which every
230
+ host does get. Tear-down removes it with the rest of the `lisa-auto-<project>-*`
231
+ set.
232
+
210
233
  **Exploratory PRD pressure gate.** `auto-start-prds=true` means "create PRDs in the ready PRD
211
234
  lifecycle when the PRD queue has capacity," not "always create a new ready PRD." The
212
235
  `exploratory-prds` automation uses the same PRD source queue and pressure roles reported by
@@ -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
- # - Across the 27 host checkouts in this fleet, 12 resolve guards at all, and
408
- # ALL TWELVE are behind or undateable. None is current. Eight carry no
409
- # apply receipt; four are behind by a whole MAJOR (3.23.0, 3.23.1, 3.46.3,
410
- # 3.54.4 against 4.17.2).
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