@codyswann/lisa 2.280.0 → 2.282.0

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 (148) hide show
  1. package/all/copy-contents/gitignore +2 -0
  2. package/dist/cli/doctor-readiness-capabilities.d.ts +33 -0
  3. package/dist/cli/doctor-readiness-capabilities.d.ts.map +1 -0
  4. package/dist/cli/doctor-readiness-capabilities.js +26 -0
  5. package/dist/cli/doctor-readiness-capabilities.js.map +1 -0
  6. package/dist/cli/doctor-readiness-domain.d.ts +17 -0
  7. package/dist/cli/doctor-readiness-domain.d.ts.map +1 -0
  8. package/dist/cli/doctor-readiness-domain.js +197 -0
  9. package/dist/cli/doctor-readiness-domain.js.map +1 -0
  10. package/dist/cli/doctor-readiness-guardrails.d.ts +15 -0
  11. package/dist/cli/doctor-readiness-guardrails.d.ts.map +1 -0
  12. package/dist/cli/doctor-readiness-guardrails.js +219 -0
  13. package/dist/cli/doctor-readiness-guardrails.js.map +1 -0
  14. package/dist/cli/doctor-readiness-operations.d.ts +103 -0
  15. package/dist/cli/doctor-readiness-operations.d.ts.map +1 -0
  16. package/dist/cli/doctor-readiness-operations.js +207 -0
  17. package/dist/cli/doctor-readiness-operations.js.map +1 -0
  18. package/dist/cli/doctor-readiness-workflows.d.ts +20 -0
  19. package/dist/cli/doctor-readiness-workflows.d.ts.map +1 -1
  20. package/dist/cli/doctor-readiness-workflows.js +29 -7
  21. package/dist/cli/doctor-readiness-workflows.js.map +1 -1
  22. package/dist/cli/doctor-readiness.d.ts.map +1 -1
  23. package/dist/cli/doctor-readiness.js +18 -12
  24. package/dist/cli/doctor-readiness.js.map +1 -1
  25. package/dist/cli/index.d.ts +3 -0
  26. package/dist/cli/index.d.ts.map +1 -1
  27. package/dist/cli/index.js +20 -15
  28. package/dist/cli/index.js.map +1 -1
  29. package/dist/cli/standards-proof-cmd.d.ts +7 -0
  30. package/dist/cli/standards-proof-cmd.d.ts.map +1 -0
  31. package/dist/cli/standards-proof-cmd.js +14 -0
  32. package/dist/cli/standards-proof-cmd.js.map +1 -0
  33. package/dist/cli/ui-setup-readiness-local.d.ts +2 -1
  34. package/dist/cli/ui-setup-readiness-local.d.ts.map +1 -1
  35. package/dist/cli/ui-setup-readiness-local.js +4 -2
  36. package/dist/cli/ui-setup-readiness-local.js.map +1 -1
  37. package/dist/cli/ui-setup-readiness.d.ts.map +1 -1
  38. package/dist/cli/ui-setup-readiness.js +3 -2
  39. package/dist/cli/ui-setup-readiness.js.map +1 -1
  40. package/dist/cli/update-check-hook.d.ts +19 -0
  41. package/dist/cli/update-check-hook.d.ts.map +1 -0
  42. package/dist/cli/update-check-hook.js +36 -0
  43. package/dist/cli/update-check-hook.js.map +1 -0
  44. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  45. package/dist/core/upstream-evidence-manifest.js +47 -6
  46. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  47. package/dist/standards/capture.d.ts +41 -0
  48. package/dist/standards/capture.d.ts.map +1 -0
  49. package/dist/standards/capture.js +196 -0
  50. package/dist/standards/capture.js.map +1 -0
  51. package/dist/standards/contract.d.ts +45 -0
  52. package/dist/standards/contract.d.ts.map +1 -0
  53. package/dist/standards/contract.js +175 -0
  54. package/dist/standards/contract.js.map +1 -0
  55. package/dist/standards/git-state.d.ts +30 -0
  56. package/dist/standards/git-state.d.ts.map +1 -0
  57. package/dist/standards/git-state.js +179 -0
  58. package/dist/standards/git-state.js.map +1 -0
  59. package/dist/standards/index.d.ts +8 -0
  60. package/dist/standards/index.d.ts.map +1 -0
  61. package/dist/standards/index.js +8 -0
  62. package/dist/standards/index.js.map +1 -0
  63. package/dist/standards/readiness.d.ts +11 -0
  64. package/dist/standards/readiness.d.ts.map +1 -0
  65. package/dist/standards/readiness.js +170 -0
  66. package/dist/standards/readiness.js.map +1 -0
  67. package/dist/standards/registry.d.ts +42 -0
  68. package/dist/standards/registry.d.ts.map +1 -0
  69. package/dist/standards/registry.js +330 -0
  70. package/dist/standards/registry.js.map +1 -0
  71. package/dist/standards/storage-reasons.d.ts +15 -0
  72. package/dist/standards/storage-reasons.d.ts.map +1 -0
  73. package/dist/standards/storage-reasons.js +48 -0
  74. package/dist/standards/storage-reasons.js.map +1 -0
  75. package/dist/standards/storage.d.ts +36 -0
  76. package/dist/standards/storage.d.ts.map +1 -0
  77. package/dist/standards/storage.js +330 -0
  78. package/dist/standards/storage.js.map +1 -0
  79. package/dist/standards/test-evidence.d.ts +19 -0
  80. package/dist/standards/test-evidence.d.ts.map +1 -0
  81. package/dist/standards/test-evidence.js +195 -0
  82. package/dist/standards/test-evidence.js.map +1 -0
  83. package/package.json +1 -1
  84. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  86. package/plugins/lisa/.codex-plugin/skills/lisa-doctor/SKILL.md +21 -3
  87. package/plugins/lisa/scripts/doctor-report.mjs +266 -22
  88. package/plugins/lisa/skills/lisa-doctor/SKILL.md +21 -3
  89. package/plugins/lisa-agy/plugin.json +1 -1
  90. package/plugins/lisa-agy/scripts/doctor-report.mjs +266 -22
  91. package/plugins/lisa-agy/skills/lisa-doctor/SKILL.md +21 -3
  92. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  93. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  94. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  95. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  96. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  97. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  98. package/plugins/lisa-copilot/scripts/doctor-report.mjs +266 -22
  99. package/plugins/lisa-copilot/skills/lisa-doctor/SKILL.md +21 -3
  100. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  101. package/plugins/lisa-cursor/scripts/doctor-report.mjs +266 -22
  102. package/plugins/lisa-cursor/skills/lisa-doctor/SKILL.md +21 -3
  103. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  104. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  105. package/plugins/lisa-expo-agy/plugin.json +1 -1
  106. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  107. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  108. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  109. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  110. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  111. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  112. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  113. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  114. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  115. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  116. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  117. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  118. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  119. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  120. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  121. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  122. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  123. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  124. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  125. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  126. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  127. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  128. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  129. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  130. package/plugins/lisa-rails-agy/plugin.json +1 -1
  131. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  132. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  133. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  134. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  135. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  136. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  137. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  138. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  139. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  140. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  141. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  142. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  143. package/plugins/src/base/scripts/doctor-report.mjs +266 -22
  144. package/plugins/src/base/skills/lisa-doctor/SKILL.md +21 -3
  145. package/rails/copy-overwrite/lefthook.yml +9 -11
  146. package/rails/copy-overwrite/scripts/lisa-clean-git-env.sh +13 -0
  147. package/typescript/copy-contents/.husky/pre-push +9 -0
  148. package/ui/index.html +3 -2
@@ -0,0 +1,330 @@
1
+ /** Confined, bounded, atomic storage for standards-conformance proof. */
2
+ import * as fse from "fs-extra";
3
+ import { constants as fsConstants } from "node:fs";
4
+ import { lstat, open, realpath, rename, rm } from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { withFileTargetLock } from "../core/learnings-lock.js";
7
+ import { syncContainingDirectory } from "../health/directory-sync.js";
8
+ import { STANDARDS_PROOF_PATH, validateStandardsProof, } from "./contract.js";
9
+ import { MALFORMED_STANDARDS_PROOF_REASON, safeStandardsStorageReason, safeStandardsValidationReason, } from "./storage-reasons.js";
10
+ export const MAX_STANDARDS_PROOF_BYTES = 128 * 1024;
11
+ const PROOF_TOO_LARGE = "Standards proof exceeds 128 KiB";
12
+ const UNSAFE_PROOF_TARGET = "Unsafe standards proof target";
13
+ /**
14
+ * Read strict proof state without throwing for runtime-state faults.
15
+ * @param projectRoot - Project directory containing the proof
16
+ * @param now - Observation time for future-timestamp rejection
17
+ * @param dependencies - Test-only timing dependencies
18
+ * @returns Closed proof read result
19
+ */
20
+ export async function readStandardsProof(projectRoot, now = new Date(), dependencies = {}) {
21
+ const payload = await readProofPayload(projectRoot, dependencies);
22
+ if (typeof payload !== "string")
23
+ return payload;
24
+ const parsed = parseProofPayload(payload);
25
+ if (parsed.status === "unreadable")
26
+ return parsed;
27
+ try {
28
+ return Object.freeze({
29
+ status: "available",
30
+ proof: validateStandardsProof(parsed.candidate, now),
31
+ });
32
+ }
33
+ catch (error) {
34
+ return unreadable(safeStandardsValidationReason(error));
35
+ }
36
+ }
37
+ /**
38
+ * Parse a bounded proof payload into untrusted data.
39
+ * @param payload - UTF-8 JSON payload
40
+ * @returns Parsed candidate or a safe unreadable result
41
+ */
42
+ function parseProofPayload(payload) {
43
+ try {
44
+ return Object.freeze({
45
+ status: "parsed",
46
+ candidate: JSON.parse(payload),
47
+ });
48
+ }
49
+ catch {
50
+ return unreadable(MALFORMED_STANDARDS_PROOF_REASON);
51
+ }
52
+ }
53
+ /**
54
+ * Read a proof payload while converting storage faults to closed results.
55
+ * @param projectRoot - Project directory containing the proof
56
+ * @param dependencies - Test-only timing dependencies
57
+ * @returns Raw payload or a closed proof read result
58
+ */
59
+ async function readProofPayload(projectRoot, dependencies) {
60
+ try {
61
+ const target = await resolveReadTarget(projectRoot);
62
+ const payload = await readBoundedRegularFile(target, dependencies);
63
+ return payload === undefined
64
+ ? Object.freeze({ status: "missing" })
65
+ : payload;
66
+ }
67
+ catch (error) {
68
+ return unreadable(safeStandardsStorageReason(error));
69
+ }
70
+ }
71
+ /**
72
+ * Construct an immutable unreadable result.
73
+ * @param reason - Sanitized operator-facing reason
74
+ * @returns Closed unreadable result
75
+ */
76
+ function unreadable(reason) {
77
+ return Object.freeze({ status: "unreadable", reason });
78
+ }
79
+ /**
80
+ * Validate and atomically replace the proof only after capture succeeds.
81
+ * @param projectRoot - Project directory that owns the proof
82
+ * @param candidate - Untrusted proof candidate
83
+ * @param now - Validation time for future-timestamp rejection
84
+ * @returns Stored path and immutable proof
85
+ */
86
+ export async function writeStandardsProof(projectRoot, candidate, now = new Date()) {
87
+ const proof = validateStandardsProof(candidate, now);
88
+ const serialized = serialize(proof);
89
+ const { directory, target } = await resolveWriteTarget(projectRoot);
90
+ return await withFileTargetLock(target, async () => {
91
+ await assertSafeTarget(target);
92
+ const temporary = path.join(directory, `.${path.basename(target)}.${process.pid}.${crypto.randomUUID()}.tmp`);
93
+ try {
94
+ const handle = await open(temporary, "wx", 0o600);
95
+ try {
96
+ await handle.writeFile(serialized, "utf8");
97
+ await handle.sync();
98
+ }
99
+ finally {
100
+ await handle.close();
101
+ }
102
+ await assertSafeTarget(target);
103
+ await rename(temporary, target);
104
+ await syncContainingDirectory(directory);
105
+ }
106
+ finally {
107
+ await rm(temporary, { force: true });
108
+ }
109
+ return Object.freeze({ path: target, proof });
110
+ });
111
+ }
112
+ /**
113
+ * Serialize a proof within its storage budget.
114
+ * @param proof - Validated proof
115
+ * @returns Canonical JSON file payload
116
+ */
117
+ function serialize(proof) {
118
+ const payload = `${JSON.stringify(proof, null, 2)}\n`;
119
+ if (Buffer.byteLength(payload, "utf8") > MAX_STANDARDS_PROOF_BYTES) {
120
+ throw new Error(PROOF_TOO_LARGE);
121
+ }
122
+ return payload;
123
+ }
124
+ /**
125
+ * Resolve and validate a real project directory.
126
+ * @param projectRoot - Candidate project directory
127
+ * @returns Canonical project directory
128
+ */
129
+ async function requireProjectRoot(projectRoot) {
130
+ const root = await realpath(path.resolve(projectRoot));
131
+ const metadata = await lstat(root);
132
+ if (!metadata.isDirectory())
133
+ throw new Error("Project root is not a directory");
134
+ return root;
135
+ }
136
+ /**
137
+ * Resolve a confined proof read target without creating directories.
138
+ * @param projectRoot - Project directory containing the proof
139
+ * @returns Confined proof path
140
+ */
141
+ async function resolveReadTarget(projectRoot) {
142
+ const root = await requireProjectRoot(projectRoot);
143
+ for (const directory of [
144
+ path.join(root, ".lisa"),
145
+ path.join(root, ".lisa", "standards"),
146
+ ]) {
147
+ if ((await statPath(directory)) !== undefined) {
148
+ await assertConfinedDirectory(root, directory);
149
+ }
150
+ }
151
+ return path.join(root, STANDARDS_PROOF_PATH);
152
+ }
153
+ /**
154
+ * Resolve and prepare a confined proof write target.
155
+ * @param projectRoot - Project directory that owns the proof
156
+ * @returns Confined storage directory and proof path
157
+ */
158
+ async function resolveWriteTarget(projectRoot) {
159
+ const root = await requireProjectRoot(projectRoot);
160
+ const lisa = path.join(root, ".lisa");
161
+ const directory = path.join(lisa, "standards");
162
+ await ensureSafeDirectory(root, lisa);
163
+ await ensureSafeDirectory(root, directory);
164
+ return { directory, target: path.join(directory, "latest.json") };
165
+ }
166
+ /**
167
+ * Create a directory only through a confined real parent.
168
+ * @param root - Canonical project directory
169
+ * @param directory - Directory to validate or create
170
+ */
171
+ async function ensureSafeDirectory(root, directory) {
172
+ if ((await statPath(directory)) !== undefined) {
173
+ await assertConfinedDirectory(root, directory);
174
+ return;
175
+ }
176
+ await assertConfinedDirectory(root, path.dirname(directory));
177
+ await fse.ensureDir(directory);
178
+ await assertConfinedDirectory(root, directory);
179
+ }
180
+ /**
181
+ * Require a real directory confined beneath the project root.
182
+ * @param root - Canonical project directory
183
+ * @param directory - Directory to validate
184
+ */
185
+ async function assertConfinedDirectory(root, directory) {
186
+ const metadata = await lstat(directory);
187
+ if (!metadata.isDirectory() || metadata.isSymbolicLink()) {
188
+ throw new Error("Unsafe standards storage parent");
189
+ }
190
+ const actual = await realpath(directory);
191
+ if (actual !== root && !actual.startsWith(`${root}${path.sep}`)) {
192
+ throw new Error("Unsafe standards storage parent escapes project root");
193
+ }
194
+ }
195
+ /**
196
+ * Reject an existing proof target unless it is a regular file.
197
+ * @param target - Proof path to validate
198
+ */
199
+ async function assertSafeTarget(target) {
200
+ try {
201
+ const metadata = await lstat(target);
202
+ if (!metadata.isFile() || metadata.isSymbolicLink()) {
203
+ throw new Error(UNSAFE_PROOF_TARGET);
204
+ }
205
+ }
206
+ catch (error) {
207
+ if (error.code !== "ENOENT")
208
+ throw error;
209
+ }
210
+ }
211
+ /**
212
+ * Open and read one bounded regular file without following symlinks.
213
+ * @param target - Proof path to read
214
+ * @param dependencies - Test-only timing dependencies
215
+ * @returns UTF-8 payload, or undefined when the path is absent
216
+ */
217
+ async function readBoundedRegularFile(target, dependencies) {
218
+ try {
219
+ const before = await lstat(target);
220
+ assertReadableMetadata(before);
221
+ const handle = await open(target, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_NONBLOCK);
222
+ try {
223
+ return await readOpenedProof(handle, target, before, dependencies);
224
+ }
225
+ finally {
226
+ await handle.close();
227
+ }
228
+ }
229
+ catch (error) {
230
+ if (error.code === "ENOENT")
231
+ return undefined;
232
+ if (["ELOOP", "ENXIO", "EAGAIN"].includes(error.code ?? "")) {
233
+ throw new Error(UNSAFE_PROOF_TARGET);
234
+ }
235
+ throw error;
236
+ }
237
+ }
238
+ /**
239
+ * Require regular-file metadata within the proof size budget.
240
+ * @param metadata - Filesystem metadata to validate
241
+ */
242
+ function assertReadableMetadata(metadata) {
243
+ if (!metadata.isFile() || metadata.isSymbolicLink()) {
244
+ throw new Error(UNSAFE_PROOF_TARGET);
245
+ }
246
+ if (metadata.size > MAX_STANDARDS_PROOF_BYTES) {
247
+ throw new Error(PROOF_TOO_LARGE);
248
+ }
249
+ }
250
+ /**
251
+ * Pin an opened proof descriptor before reading its contents.
252
+ * @param handle - Open no-follow file handle
253
+ * @param target - Proof path used for identity checks
254
+ * @param before - Metadata observed before opening
255
+ * @param dependencies - Test-only timing dependencies
256
+ * @returns Stable UTF-8 payload
257
+ */
258
+ async function readOpenedProof(handle, target, before, dependencies) {
259
+ const opened = await handle.stat();
260
+ const bytes = Buffer.alloc(MAX_STANDARDS_PROOF_BYTES + 1);
261
+ assertSameFile(before, opened);
262
+ await dependencies.afterOpen?.(target);
263
+ return await finishOpenedProofRead(handle, target, opened, bytes);
264
+ }
265
+ /**
266
+ * Read an opened proof and verify its descriptor and path remain stable.
267
+ * @param handle - Open proof file handle
268
+ * @param target - Proof path used for identity checks
269
+ * @param opened - Metadata pinned immediately after opening
270
+ * @param bytes - Fixed-size destination buffer
271
+ * @returns Stable UTF-8 payload
272
+ */
273
+ async function finishOpenedProofRead(handle, target, opened, bytes) {
274
+ const total = await readDescriptorBytes(handle, bytes);
275
+ if (total > MAX_STANDARDS_PROOF_BYTES)
276
+ throw new Error(PROOF_TOO_LARGE);
277
+ const [afterOpened, afterPath] = await Promise.all([
278
+ handle.stat(),
279
+ lstat(target),
280
+ ]);
281
+ assertSameFile(opened, afterOpened);
282
+ assertSameFile(opened, afterPath);
283
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, total));
284
+ }
285
+ /**
286
+ * Require two metadata snapshots to identify the same unchanged file.
287
+ * @param expected - Pinned metadata snapshot
288
+ * @param actual - Later metadata snapshot
289
+ */
290
+ function assertSameFile(expected, actual) {
291
+ if (!actual.isFile() ||
292
+ actual.dev !== expected.dev ||
293
+ actual.ino !== expected.ino ||
294
+ actual.size !== expected.size) {
295
+ throw new Error("Standards proof changed during read");
296
+ }
297
+ }
298
+ /**
299
+ * Fill a fixed-size buffer from an opened descriptor.
300
+ * @param handle - Open proof file handle
301
+ * @param bytes - Destination buffer
302
+ * @returns Number of bytes read
303
+ */
304
+ async function readDescriptorBytes(handle, bytes) {
305
+ // eslint-disable-next-line functional/no-let -- fixed-size descriptor read advances one bounded offset
306
+ let total = 0;
307
+ while (total < bytes.byteLength) {
308
+ const chunk = await handle.read(bytes, total, bytes.byteLength - total, total);
309
+ if (chunk.bytesRead === 0)
310
+ break;
311
+ total += chunk.bytesRead;
312
+ }
313
+ return total;
314
+ }
315
+ /**
316
+ * Read path metadata while treating absence as undefined.
317
+ * @param filePath - Filesystem path to inspect
318
+ * @returns Metadata, or undefined when absent
319
+ */
320
+ async function statPath(filePath) {
321
+ try {
322
+ return await lstat(filePath);
323
+ }
324
+ catch (error) {
325
+ if (error.code === "ENOENT")
326
+ return undefined;
327
+ throw error;
328
+ }
329
+ }
330
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/standards/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /** Positive, private-output evidence that a managed test runner executed tests. */
2
+ export declare const TEST_EVIDENCE_FORMATS: readonly ["vitest", "jest", "playwright", "rspec", "managed"];
3
+ /** Runner grammar used to prove that at least one test executed. */
4
+ export type TestEvidenceFormat = (typeof TEST_EVIDENCE_FORMATS)[number];
5
+ /**
6
+ * Require affirmative runner output for at least one executed test. A clean
7
+ * exit, an empty stream, or an all-skipped summary is never sufficient.
8
+ * @param format - Runner-specific or managed-union evidence grammar
9
+ * @param output - Bounded private stdout/stderr captured by the explicit CLI
10
+ * @returns Whether at least one test was positively reported as executed
11
+ */
12
+ export declare function hasPositiveTestEvidence(format: TestEvidenceFormat, output: string): boolean;
13
+ /**
14
+ * Select the narrowest known parser from a managed package script.
15
+ * @param script - Package-script text read from the confined manifest
16
+ * @returns Positive-evidence grammar for its runner
17
+ */
18
+ export declare function inferTestEvidenceFormat(script: string): TestEvidenceFormat;
19
+ //# sourceMappingURL=test-evidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-evidence.d.ts","sourceRoot":"","sources":["../../src/standards/test-evidence.ts"],"names":[],"mappings":"AAAA,mFAAmF;AAEnF,eAAO,MAAM,qBAAqB,+DAMxB,CAAC;AACX,oEAAoE;AACpE,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAMxE;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,MAAM,GACb,OAAO,CAgBT;AA6KD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,kBAAkB,CAO1E"}
@@ -0,0 +1,195 @@
1
+ /** Positive, private-output evidence that a managed test runner executed tests. */
2
+ export const TEST_EVIDENCE_FORMATS = [
3
+ "vitest",
4
+ "jest",
5
+ "playwright",
6
+ "rspec",
7
+ "managed",
8
+ ];
9
+ const MAX_EVIDENCE_OUTPUT_CHARACTERS = 1024 * 1024;
10
+ const MAX_EVIDENCE_LINES = 4096;
11
+ const MAX_EVIDENCE_LINE_CHARACTERS = 4096;
12
+ /**
13
+ * Require affirmative runner output for at least one executed test. A clean
14
+ * exit, an empty stream, or an all-skipped summary is never sufficient.
15
+ * @param format - Runner-specific or managed-union evidence grammar
16
+ * @param output - Bounded private stdout/stderr captured by the explicit CLI
17
+ * @returns Whether at least one test was positively reported as executed
18
+ */
19
+ export function hasPositiveTestEvidence(format, output) {
20
+ const lines = boundedTokenLines(output);
21
+ const runnerEvidence = lines.some(tokens => {
22
+ if (format === "vitest" || format === "jest") {
23
+ return isTestsSummary(tokens);
24
+ }
25
+ if (format === "playwright")
26
+ return isLeadingStatusSummary(tokens);
27
+ if (format === "rspec")
28
+ return isExamplesSummary(tokens);
29
+ return (isTestsSummary(tokens) ||
30
+ isLeadingStatusSummary(tokens) ||
31
+ isExamplesSummary(tokens) ||
32
+ isManagedTestSummary(tokens));
33
+ });
34
+ return runnerEvidence || (format === "managed" && isTapSummary(lines));
35
+ }
36
+ /**
37
+ * Split bounded output into bounded, punctuation-neutral token lines.
38
+ * @param output - Private runner output
39
+ * @returns Bounded token lines
40
+ */
41
+ function boundedTokenLines(output) {
42
+ return output
43
+ .slice(0, MAX_EVIDENCE_OUTPUT_CHARACTERS)
44
+ .split("\n", MAX_EVIDENCE_LINES)
45
+ .map(line => tokenizeLine(line.slice(0, MAX_EVIDENCE_LINE_CHARACTERS)));
46
+ }
47
+ /**
48
+ * Convert one bounded ASCII runner line to lowercase alphanumeric tokens.
49
+ * @param line - One bounded runner line
50
+ * @returns Lowercase alphanumeric tokens
51
+ */
52
+ function tokenizeLine(line) {
53
+ return Array.from(line, character => isAsciiAlphanumeric(character) ? character.toLowerCase() : " ")
54
+ .join("")
55
+ .split(" ")
56
+ .filter(Boolean);
57
+ }
58
+ /**
59
+ * Return whether one character is an ASCII letter or digit.
60
+ * @param character - Single input character
61
+ * @returns Whether the character is token-safe
62
+ */
63
+ function isAsciiAlphanumeric(character) {
64
+ const code = character.charCodeAt(0);
65
+ return ((code >= 48 && code <= 57) ||
66
+ (code >= 65 && code <= 90) ||
67
+ (code >= 97 && code <= 122));
68
+ }
69
+ /**
70
+ * Return whether a token is a nonzero base-10 integer.
71
+ * @param token - Candidate numeric token
72
+ * @returns Whether the token is positive
73
+ */
74
+ function isPositiveInteger(token) {
75
+ const value = nonnegativeIntegerValue(token);
76
+ return value !== undefined && value > 0;
77
+ }
78
+ /**
79
+ * Parse one bounded decimal token without accepting signs or fractions.
80
+ * @param token - Candidate count token
81
+ * @returns Safe nonnegative integer, when valid
82
+ */
83
+ function nonnegativeIntegerValue(token) {
84
+ if (token === undefined || token.length === 0)
85
+ return undefined;
86
+ const digitsOnly = Array.from(token).every(character => {
87
+ const code = character.charCodeAt(0);
88
+ return code >= 48 && code <= 57;
89
+ });
90
+ if (!digitsOnly)
91
+ return undefined;
92
+ const value = Number(token);
93
+ return Number.isSafeInteger(value) ? value : undefined;
94
+ }
95
+ /**
96
+ * Recognize Vitest/Jest `Tests: N passed|failed` summary fragments.
97
+ * @param tokens - One bounded token line
98
+ * @returns Whether the line proves test execution
99
+ */
100
+ function isTestsSummary(tokens) {
101
+ if (tokens[0] !== "tests")
102
+ return false;
103
+ return tokens.some((token, index) => isOutcome(token) && isPositiveInteger(tokens[index - 1]));
104
+ }
105
+ /**
106
+ * Recognize Playwright `N passed|failed` summary lines.
107
+ * @param tokens - One bounded token line
108
+ * @returns Whether the line proves test execution
109
+ */
110
+ function isLeadingStatusSummary(tokens) {
111
+ return isPositiveInteger(tokens[0]) && isOutcome(tokens[1]);
112
+ }
113
+ /**
114
+ * Recognize RSpec `N examples` summary fragments.
115
+ * @param tokens - One bounded token line
116
+ * @returns Whether the line proves example execution
117
+ */
118
+ function isExamplesSummary(tokens) {
119
+ const examples = countBeforeLabel(tokens, ["example", "examples"]);
120
+ const failures = countBeforeLabel(tokens, ["failure", "failures"]) ?? 0;
121
+ const pending = countBeforeLabel(tokens, ["pending"]) ?? 0;
122
+ return (examples !== undefined &&
123
+ examples > 0 &&
124
+ (failures > 0 || examples > pending));
125
+ }
126
+ /**
127
+ * Read the count immediately before a known summary label.
128
+ * @param tokens - One bounded token line
129
+ * @param labels - Accepted singular/plural labels
130
+ * @returns Parsed count, when present
131
+ */
132
+ function countBeforeLabel(tokens, labels) {
133
+ const index = tokens.findIndex(token => labels.includes(token));
134
+ return index < 1 ? undefined : nonnegativeIntegerValue(tokens[index - 1]);
135
+ }
136
+ /**
137
+ * Correlate bounded TAP aggregate lines and reject explicitly all-skipped runs.
138
+ * @param lines - Bounded token lines
139
+ * @returns Whether TAP proves at least one actual execution
140
+ */
141
+ function isTapSummary(lines) {
142
+ const tests = tapAggregate(lines, ["tests"]);
143
+ if (tests === undefined || tests === 0)
144
+ return false;
145
+ const passed = tapAggregate(lines, ["pass", "passed"]);
146
+ const failed = tapAggregate(lines, ["fail", "failed"]);
147
+ const executed = (passed ?? 0) + (failed ?? 0);
148
+ return executed > 0 && executed <= tests;
149
+ }
150
+ /**
151
+ * Read one exact two-token TAP aggregate line.
152
+ * @param lines - Bounded token lines
153
+ * @param labels - Accepted aggregate labels
154
+ * @returns Parsed aggregate count, when present
155
+ */
156
+ function tapAggregate(lines, labels) {
157
+ const line = lines.find(tokens => tokens.length === 2 && labels.includes(tokens[0] ?? ""));
158
+ return line === undefined ? undefined : nonnegativeIntegerValue(line[1]);
159
+ }
160
+ /**
161
+ * Recognize generic managed-runner `N test(s) passed|failed` summaries.
162
+ * @param tokens - One bounded token line
163
+ * @returns Whether the line proves test execution
164
+ */
165
+ function isManagedTestSummary(tokens) {
166
+ return (isPositiveInteger(tokens[0]) &&
167
+ (tokens[1] === "test" || tokens[1] === "tests") &&
168
+ isOutcome(tokens[2]));
169
+ }
170
+ /**
171
+ * Return whether a summary token represents an executed test outcome.
172
+ * @param token - Candidate outcome token
173
+ * @returns Whether it is a pass/fail outcome
174
+ */
175
+ function isOutcome(token) {
176
+ return token === "passed" || token === "failed";
177
+ }
178
+ /**
179
+ * Select the narrowest known parser from a managed package script.
180
+ * @param script - Package-script text read from the confined manifest
181
+ * @returns Positive-evidence grammar for its runner
182
+ */
183
+ export function inferTestEvidenceFormat(script) {
184
+ const normalized = script.toLowerCase();
185
+ if (normalized.includes("vitest"))
186
+ return "vitest";
187
+ if (normalized.includes("playwright"))
188
+ return "playwright";
189
+ if (normalized.includes("jest"))
190
+ return "jest";
191
+ if (normalized.includes("rspec"))
192
+ return "rspec";
193
+ return "managed";
194
+ }
195
+ //# sourceMappingURL=test-evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-evidence.js","sourceRoot":"","sources":["../../src/standards/test-evidence.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -112,7 +112,7 @@
112
112
  "brace-expansion": ">=5.0.6"
113
113
  },
114
114
  "name": "@codyswann/lisa",
115
- "version": "2.280.0",
115
+ "version": "2.282.0",
116
116
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
117
117
  "main": "dist/index.js",
118
118
  "exports": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.280.0",
3
+ "version": "2.282.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.280.0",
3
+ "version": "2.282.0",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -319,9 +319,27 @@ default doctor path never renders it and stays byte-identical.
319
319
  contract; do not restate or fork that vocabulary here.
320
320
  3. **`SKIP` carries a reason and is never blank.** A dimension with no applicable evidence renders
321
321
  `SKIP` with a stated reason ("no deployment target configured, so delivery/authority was not
322
- assessed"). An unassessed dimension is a known unknown, and the report says so. In Lisa versions
323
- where the evidence-gathering surfaces (RRR-4/5/6) are not yet wired, every dimension renders `SKIP`
324
- with that reason.
322
+ assessed"). An unassessed dimension is a known unknown, and the report says so.
323
+
324
+ **This surface reflects the CLI; it does not re-score.** The evidence producers and the blocker
325
+ engine live in the Lisa CLI, which is the single source of truth. When `.lisa/readiness.json` is
326
+ present and readable (parses, matching `schema_version`, carries a `dimensions` array), this group
327
+ **projects** each recorded dimension's status and its operator-facing evidence/reason text, so an
328
+ operator running `/lisa:doctor` through any coding agent sees the same readiness answer the CLI
329
+ gives. When the report is absent, unparseable, or stamped with an unknown `schema_version` — or
330
+ records nothing for a given dimension — that dimension falls back to `SKIP` with the reason it was
331
+ not assessed. Absence means the readiness pass has not run, never that the repository is clean: a
332
+ pass or a fail is never manufactured from a missing report. Run
333
+ `lisa doctor --offline --readiness` to produce the report first.
334
+
335
+ **A standing blocker outranks the recorded status.** Some CLI producers record `WARN` while
336
+ standing a ship blocker — the blocker engine never reads the per-dimension status, so the finding
337
+ flips the repository to `NOT_READY` exactly as a `FAIL` would. A dimension that owns an entry in
338
+ the report's `blockers[]` therefore projects as `FAIL` regardless of its recorded label, and its
339
+ remediation names the blocker ids and repeats the report's `narrowed_claim` (the "IS ready for
340
+ supervised, single-ticket agent work" fallback `readiness-rubric` requires whenever a blocker
341
+ stands). Projected checks also carry the report's `generated_at`/`lisa_version` so a stale report
342
+ cannot read as current truth, and unassessed dimensions carry the CLI's not-established caveat.
325
343
  4. **Reuse the shipped verdict ladder and consequence ordering.** No new verdict value and no new
326
344
  severity: reuse `READY` / `READY_WITH_WARNINGS` / `NOT_READY`. `READY` requires *positive*
327
345
  evidence — every readiness dimension assessed and clean, with no blocker standing. An unassessed