@codyswann/lisa 4.66.5 → 4.67.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 (70) hide show
  1. package/all/copy-overwrite/scripts/lisa-self-update.mjs +636 -0
  2. package/all/create-only/.github/workflows/lisa-update.yml +93 -0
  3. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  4. package/dist/core/lisa-owned-hash-ledger.js +10 -0
  5. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  6. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  7. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  8. package/dist/core/upstream-evidence-manifest.js +14 -3
  9. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  10. package/package.json +4 -4
  11. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  12. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  13. package/plugins/lisa/hooks/enforcement-vintage-npm.mjs +320 -0
  14. package/plugins/lisa/hooks/enforcement-vintage.mjs +22 -3
  15. package/plugins/lisa-agy/plugin.json +1 -1
  16. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  17. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  19. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  21. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-copilot/hooks/enforcement-vintage-npm.mjs +320 -0
  23. package/plugins/lisa-copilot/hooks/enforcement-vintage.mjs +22 -3
  24. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  25. package/plugins/lisa-cursor/hooks/enforcement-vintage-npm.mjs +320 -0
  26. package/plugins/lisa-cursor/hooks/enforcement-vintage.mjs +22 -3
  27. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  29. package/plugins/lisa-expo-agy/plugin.json +1 -1
  30. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  31. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  34. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  35. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  39. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  40. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  44. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  45. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  46. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  49. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  50. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  54. package/plugins/lisa-rails-agy/plugin.json +1 -1
  55. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  59. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  60. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  64. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  65. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  67. package/plugins/src/base/hooks/enforcement-vintage-npm.mjs +320 -0
  68. package/plugins/src/base/hooks/enforcement-vintage.mjs +22 -3
  69. package/scripts/two-channel-couplings.json +1 -1
  70. package/typescript/copy-overwrite/.prettierignore +1 -0
package/package.json CHANGED
@@ -187,7 +187,7 @@
187
187
  "zod-validation-error": "^4.0.0"
188
188
  },
189
189
  "name": "@codyswann/lisa",
190
- "version": "4.66.5",
190
+ "version": "4.67.0",
191
191
  "description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
192
192
  "main": "dist/index.js",
193
193
  "exports": {
@@ -336,7 +336,7 @@
336
336
  "test": "tests"
337
337
  },
338
338
  "types": "./dist/index.d.ts",
339
- "lisaReleaseCommit": "cf55d5f03806fa21e346c1bec6f45110030a13e2",
340
- "gitHead": "cf55d5f03806fa21e346c1bec6f45110030a13e2",
341
- "lisaReleaseTag": "v4.66.5"
339
+ "lisaReleaseCommit": "4bb326e655301ad1188a57583b804fc03fe29003",
340
+ "gitHead": "4bb326e655301ad1188a57583b804fc03fe29003",
341
+ "lisaReleaseTag": "v4.67.0"
342
342
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.66.5",
3
+ "version": "4.67.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": "4.66.5",
3
+ "version": "4.67.0",
4
4
  "description": "Universal governance: agents, skills, commands, hooks, and rules for all projects.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -0,0 +1,320 @@
1
+ /**
2
+ * The two rows `enforcement-vintage` could not show before: the Lisa version the
3
+ * PROJECT installed, and the newest Lisa PUBLISHED (CodySwannGT/lisa#4325).
4
+ *
5
+ * Why these two. The session-copy rows answer "is this session running the
6
+ * newest Lisa on this disk?" — and a whole host can be current by that measure
7
+ * while sitting many releases behind npm, because nothing on the disk is newer
8
+ * than the version the project last installed. A host only moves when something
9
+ * opens an update PR for it. The agent standing in that host is the party most
10
+ * able to notice and least likely to be told, so the comparison goes where the
11
+ * agent reads: the injected context.
12
+ *
13
+ * NO NETWORK ON THE STARTUP PATH. A session start must never wait on npm. The
14
+ * row is read from the cache the `lisa` CLI's own update check already writes
15
+ * (`node_modules/.cache/@codyswann/lisa/update-check.json`, same shape, same
16
+ * 6-hour freshness), so the two surfaces cannot disagree about "latest". When
17
+ * that cache is missing or stale, a DETACHED child refreshes it for the next
18
+ * session and this session reports what it has — a stale reading named as
19
+ * stale, never a guess.
20
+ *
21
+ * FAIL SOFT, ALWAYS. Every function here returns a neutral value on any error.
22
+ * @module plugins/src/base/hooks/enforcement-vintage-npm
23
+ */
24
+ import { spawn } from "child_process";
25
+ import { mkdirSync, readFileSync, realpathSync, writeFileSync } from "fs";
26
+ import path from "path";
27
+ import { fileURLToPath } from "url";
28
+
29
+ /** The package whose versions are compared. */
30
+ export const LISA_PACKAGE = "@codyswann/lisa";
31
+
32
+ /** Same freshness window as the CLI update check (`src/cli/update-check.ts`). */
33
+ export const NPM_LATEST_TTL_MS = 6 * 60 * 60 * 1000;
34
+
35
+ /** Budget for the detached refresh; it runs after the session has started. */
36
+ const REFRESH_TIMEOUT_MS = 5000;
37
+
38
+ /**
39
+ * Registry endpoint for the latest dist-tag.
40
+ *
41
+ * The cached mutable pointer lags a publish by minutes (CodySwannGT/lisa#3685).
42
+ * That is fine here for the same reason it is fine in the CLI nag: nothing
43
+ * downstream of this value chooses, publishes or gates — it is advice.
44
+ */
45
+ const NPM_LATEST_URL = "https://registry.npmjs.org/@codyswann/lisa/latest";
46
+
47
+ /** A plain `x.y.z` release, optionally with a prerelease or build suffix. */
48
+ const VERSION_SHAPE = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.+-]+)?$/u;
49
+
50
+ /**
51
+ * Compare two prerelease identifier lists by semver precedence.
52
+ * @param {string[]} a Identifiers of the first prerelease.
53
+ * @param {string[]} b Identifiers of the second prerelease.
54
+ * @returns {number} Negative when `a` precedes `b`, positive when it follows.
55
+ */
56
+ function comparePrerelease(a, b) {
57
+ for (let index = 0; index < Math.max(a.length, b.length); index += 1) {
58
+ if (a[index] === undefined) return -1;
59
+ if (b[index] === undefined) return 1;
60
+ if (a[index] === b[index]) continue;
61
+ const numeric = /^\d+$/u;
62
+ if (numeric.test(a[index]) && numeric.test(b[index])) {
63
+ return Number(a[index]) - Number(b[index]);
64
+ }
65
+ if (numeric.test(a[index])) return -1;
66
+ if (numeric.test(b[index])) return 1;
67
+ return a[index] < b[index] ? -1 : 1;
68
+ }
69
+ return 0;
70
+ }
71
+
72
+ /**
73
+ * Whether version `a` has lower semver precedence than `b`.
74
+ *
75
+ * Prerelease-aware on purpose: a project pinned to `4.66.5-rc.1` is BEHIND a
76
+ * published `4.66.5`, and comparing release fields alone would call it current.
77
+ * Build metadata is ignored, as semver requires.
78
+ * @param {string} a Candidate older version.
79
+ * @param {string} b Candidate newer version.
80
+ * @returns {boolean} True when `a` precedes `b`.
81
+ */
82
+ export function precedes(a, b) {
83
+ const split = version => {
84
+ const [core, pre] = String(version).split("+")[0].split(/-(.*)/su);
85
+ const fields = core.split(".").map(field => Number(field) || 0);
86
+ return { fields, pre: pre ? pre.split(".") : [] };
87
+ };
88
+ const left = split(a);
89
+ const right = split(b);
90
+ for (let index = 0; index < 3; index += 1) {
91
+ const l = left.fields[index] ?? 0;
92
+ const r = right.fields[index] ?? 0;
93
+ if (l !== r) return l < r;
94
+ }
95
+ if (left.pre.length === 0) return false;
96
+ if (right.pre.length === 0) return true;
97
+ return comparePrerelease(left.pre, right.pre) < 0;
98
+ }
99
+
100
+ /**
101
+ * Parse a JSON file, or return null.
102
+ * @param {string} file Absolute path.
103
+ * @returns {any} Parsed JSON, or null when unreadable or malformed.
104
+ */
105
+ function readJson(file) {
106
+ try {
107
+ return JSON.parse(readFileSync(file, "utf8"));
108
+ } catch {
109
+ return null;
110
+ }
111
+ }
112
+
113
+ /**
114
+ * The update-check cache path for a project — the CLI's own path.
115
+ * @param {string} projectDir Project root.
116
+ * @returns {string} Absolute cache path.
117
+ */
118
+ export function npmLatestCachePath(projectDir) {
119
+ return path.join(
120
+ projectDir,
121
+ "node_modules",
122
+ ".cache",
123
+ "@codyswann",
124
+ "lisa",
125
+ "update-check.json"
126
+ );
127
+ }
128
+
129
+ /**
130
+ * The Lisa version this project installed, or null when it has none to show.
131
+ *
132
+ * Null inside the Lisa monorepo itself: there `node_modules/@codyswann/lisa` is
133
+ * a fixture pinned majors behind the repository, and reporting it as the
134
+ * project's pin would tell every Lisa session its project is stale.
135
+ * @param {string} projectDir Project root.
136
+ * @returns {{version: string, source: string} | null} The installed copy.
137
+ */
138
+ export function projectPin(projectDir) {
139
+ const own = readJson(path.join(projectDir, "package.json"));
140
+ if (own?.name === LISA_PACKAGE) return null;
141
+ const source = path.join(
142
+ projectDir,
143
+ "node_modules",
144
+ "@codyswann",
145
+ "lisa",
146
+ "package.json"
147
+ );
148
+ const version = readJson(source)?.version;
149
+ return typeof version === "string" && VERSION_SHAPE.test(version)
150
+ ? { version, source }
151
+ : null;
152
+ }
153
+
154
+ /**
155
+ * Read the cached npm latest.
156
+ * @param {string} cachePath Absolute cache path.
157
+ * @param {number} nowMs Current time in ms.
158
+ * @param {number} [ttlMs] Freshness window.
159
+ * @returns {{version: string, fetchedAt: string, fresh: boolean} | null} Cached value.
160
+ */
161
+ export function cachedNpmLatest(cachePath, nowMs, ttlMs = NPM_LATEST_TTL_MS) {
162
+ const cache = readJson(cachePath);
163
+ const version = cache?.latest;
164
+ const fetchedAt = cache?.fetchedAt;
165
+ if (typeof version !== "string" || !VERSION_SHAPE.test(version)) return null;
166
+ if (typeof fetchedAt !== "string") return null;
167
+ const fetchedMs = Date.parse(fetchedAt);
168
+ if (!Number.isFinite(fetchedMs)) return null;
169
+ return { version, fetchedAt, fresh: nowMs - fetchedMs <= ttlMs };
170
+ }
171
+
172
+ /**
173
+ * Whether a refresh should be started for this session.
174
+ * @param {{version: string, fresh: boolean} | null} cached Cached value.
175
+ * @param {NodeJS.ProcessEnv} env Environment.
176
+ * @returns {boolean} True when the cache is missing or stale and checks are on.
177
+ */
178
+ export function needsRefresh(cached, env) {
179
+ if (env.LISA_SKIP_UPDATE_CHECK === "1") return false;
180
+ return cached === null || !cached.fresh;
181
+ }
182
+
183
+ /**
184
+ * Start a detached refresh of the cache and return immediately.
185
+ * @param {string} script Absolute path of this module.
186
+ * @param {string} cachePath Absolute cache path.
187
+ * @param {typeof spawn} [spawnImpl] Injected for tests.
188
+ * @returns {boolean} Whether a child was started.
189
+ */
190
+ export function startDetachedRefresh(script, cachePath, spawnImpl = spawn) {
191
+ try {
192
+ const child = spawnImpl(
193
+ process.execPath,
194
+ [script, "--refresh-npm-latest", cachePath],
195
+ { detached: true, stdio: "ignore" }
196
+ );
197
+ child.on?.("error", () => {});
198
+ child.unref?.();
199
+ return true;
200
+ } catch {
201
+ return false;
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Fetch npm latest and write it to the cache in the CLI's shape.
207
+ *
208
+ * probe-direction: neutral — a failed fetch writes nothing, so the next
209
+ * session reports "npm latest: unknown" (or the older cached value, labelled
210
+ * stale); no gate reads this value, it only shapes advisory context.
211
+ * @param {string} cachePath Absolute cache path.
212
+ * @param {{fetchImpl?: typeof fetch, now?: () => Date}} [deps] Injected for tests.
213
+ * @returns {Promise<string | null>} The version written, or null.
214
+ */
215
+ export async function refreshNpmLatest(cachePath, deps = {}) {
216
+ const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
217
+ const now = deps.now ?? (() => new Date());
218
+ try {
219
+ const response = await fetchImpl(NPM_LATEST_URL, {
220
+ signal: AbortSignal.timeout(REFRESH_TIMEOUT_MS),
221
+ });
222
+ if (!response.ok) return null;
223
+ const body = await response.json();
224
+ const version = body?.version;
225
+ if (typeof version !== "string" || !VERSION_SHAPE.test(version)) {
226
+ return null;
227
+ }
228
+ mkdirSync(path.dirname(cachePath), { recursive: true });
229
+ writeFileSync(
230
+ cachePath,
231
+ `${JSON.stringify({ latest: version, fetchedAt: now().toISOString() }, null, 2)}\n`,
232
+ "utf8"
233
+ );
234
+ return version;
235
+ } catch {
236
+ return null;
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Render the project and npm rows, plus the guidance when the project is behind.
242
+ * @param {{pin: {version: string, source: string} | null, latest: {version: string, fetchedAt: string, fresh: boolean} | null, refreshing: boolean, projectBehind: boolean}} state Resolved rows.
243
+ * @returns {{rows: string[], guidance: string[]}} Lines to splice into the block.
244
+ */
245
+ export function renderNpmRows(state) {
246
+ const rows = [];
247
+ if (state.pin) {
248
+ rows.push(`project pin: lisa ${state.pin.version} at ${state.pin.source}`);
249
+ }
250
+ if (state.latest) {
251
+ rows.push(
252
+ `npm latest: lisa ${state.latest.version} (checked ${state.latest.fetchedAt}${state.latest.fresh ? "" : "; stale"}${state.refreshing ? ", refreshing for the next session" : ""})`
253
+ );
254
+ } else if (state.pin) {
255
+ rows.push(
256
+ `npm latest: unknown${state.refreshing ? " (checking in the background for the next session)" : ""}`
257
+ );
258
+ }
259
+ const guidance = state.projectBehind
260
+ ? [
261
+ `PROJECT BEHIND — this project installs lisa ${state.pin?.version} while lisa ${state.latest?.version} is published.`,
262
+ "- Do NOT upgrade Lisa inside the current task: a version bump plus its template apply belongs in its own pull request, never mixed into feature work.",
263
+ "- Check for an open pull request on a `lisa/update-*` branch. If none is open, the project's Lisa Update workflow (`.github/workflows/lisa-update.yml`) opens one on its schedule; say so in your report, and if that workflow is missing, recommend running `lisa apply` once so the project receives it.",
264
+ ]
265
+ : [];
266
+ return { rows, guidance };
267
+ }
268
+
269
+ /**
270
+ * Resolve everything the npm rows need, starting a refresh when warranted.
271
+ * @param {{projectDir: string, script?: string, env: NodeJS.ProcessEnv, nowMs: number, spawnImpl?: typeof spawn}} input Inputs.
272
+ * @returns {{pin: {version: string, source: string} | null, latest: {version: string, fetchedAt: string, fresh: boolean} | null, refreshing: boolean, projectBehind: boolean}} Resolved rows.
273
+ */
274
+ export function resolveNpmState(input) {
275
+ try {
276
+ const pin = projectPin(input.projectDir);
277
+ if (pin === null) {
278
+ return { pin, latest: null, refreshing: false, projectBehind: false };
279
+ }
280
+ const cachePath = npmLatestCachePath(input.projectDir);
281
+ const latest = cachedNpmLatest(cachePath, input.nowMs);
282
+ const refreshing =
283
+ needsRefresh(latest, input.env) &&
284
+ startDetachedRefresh(
285
+ input.script ?? fileURLToPath(import.meta.url),
286
+ cachePath,
287
+ input.spawnImpl
288
+ );
289
+ const projectBehind = Boolean(
290
+ latest && precedes(pin.version, latest.version)
291
+ );
292
+ return { pin, latest, refreshing, projectBehind };
293
+ } catch {
294
+ return { pin: null, latest: null, refreshing: false, projectBehind: false };
295
+ }
296
+ }
297
+
298
+ /**
299
+ * Whether this module is the process entry point (the detached refresh child).
300
+ * Realpaths both sides for the reason `enforcement-vintage.mjs` gives.
301
+ * @param {string} moduleUrl This module's `import.meta.url`.
302
+ * @param {string | undefined} [argv1] Entry path.
303
+ * @returns {boolean} True when run directly.
304
+ */
305
+ function invokedDirectly(moduleUrl, argv1 = process.argv[1]) {
306
+ if (!argv1) return false;
307
+ try {
308
+ return realpathSync(argv1) === realpathSync(fileURLToPath(moduleUrl));
309
+ } catch {
310
+ return false;
311
+ }
312
+ }
313
+
314
+ if (
315
+ invokedDirectly(import.meta.url) &&
316
+ process.argv[2] === "--refresh-npm-latest" &&
317
+ process.argv[3]
318
+ ) {
319
+ refreshNpmLatest(process.argv[3]).catch(() => {});
320
+ }
@@ -52,6 +52,7 @@ import { readFileSync, existsSync } from "fs";
52
52
  import path from "path";
53
53
  import { fileURLToPath } from "url";
54
54
  import { realpathSync } from "fs";
55
+ import { renderNpmRows, resolveNpmState } from "./enforcement-vintage-npm.mjs";
55
56
 
56
57
  /** Marker the block is wrapped in, so an agent can cite it by name. */
57
58
  const BLOCK_TAG = "lisa-enforcement-vintage";
@@ -336,6 +337,15 @@ export function renderBlock(state) {
336
337
  `newest on this disk: lisa ${state.newest.version} at ${state.newest.source}`
337
338
  );
338
339
  }
340
+ const npm = renderNpmRows(
341
+ state.npm ?? {
342
+ pin: null,
343
+ latest: null,
344
+ refreshing: false,
345
+ projectBehind: false,
346
+ }
347
+ );
348
+ npm.rows.forEach(row => lines.push(row));
339
349
  lines.push("");
340
350
  if (state.behind || !state.running.version || state.treeBehind) {
341
351
  lines.push(
@@ -363,6 +373,10 @@ export function renderBlock(state) {
363
373
  "when you report on guard or contract behaviour; it is only current until the next release."
364
374
  );
365
375
  }
376
+ if (npm.guidance.length > 0) {
377
+ lines.push("");
378
+ npm.guidance.forEach(line => lines.push(line));
379
+ }
366
380
  lines.push(`</${BLOCK_TAG}>`);
367
381
  return lines.join("\n");
368
382
  }
@@ -405,9 +419,14 @@ export function run(argv, stdin, env = process.env) {
405
419
  return JSON.stringify({
406
420
  hookSpecificOutput: {
407
421
  hookEventName: eventName(stdin),
408
- additionalContext: renderBlock(
409
- resolveState({ hooksDir, projectDir, configDir })
410
- ),
422
+ additionalContext: renderBlock({
423
+ ...resolveState({ hooksDir, projectDir, configDir }),
424
+ npm: resolveNpmState({
425
+ projectDir,
426
+ env,
427
+ nowMs: Date.now(),
428
+ }),
429
+ }),
411
430
  },
412
431
  });
413
432
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.66.5",
3
+ "version": "4.67.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-cdk",
3
- "version": "4.66.5",
3
+ "version": "4.67.0",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.66.5",
3
+ "version": "4.67.0",
4
4
  "description": "AWS CDK-specific Lisa plugin.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.66.5",
3
+ "version": "4.67.0",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.66.5",
3
+ "version": "4.67.0",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-cdk",
3
- "version": "4.66.5",
3
+ "version": "4.67.0",
4
4
  "description": "AWS CDK-specific plugin",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "4.66.5",
3
+ "version": "4.67.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"