@codyswann/lisa 4.73.8 → 4.74.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 (113) hide show
  1. package/README.md +52 -3
  2. package/all/copy-overwrite/scripts/lib/github-attestation-recovery.mjs +48 -35
  3. package/all/copy-overwrite/scripts/lib/npm-update-hosted-gate.mjs +15 -1
  4. package/all/copy-overwrite/scripts/lib/npm-update-hosted-hook.mjs +56 -27
  5. package/all/copy-overwrite/scripts/lib/npm-update-invariants.mjs +78 -1
  6. package/all/copy-overwrite/scripts/lib/npm-update-native-process.mjs +29 -10
  7. package/all/copy-overwrite/scripts/lisa-automation-provenance.mjs +86 -37
  8. package/all/copy-overwrite/scripts/npm-updater-helper-graph.json +11 -8
  9. package/all/create-only/.github/workflows/continuous-gates.yml +2 -2
  10. package/all/create-only/.github/workflows/workflow-load-failure-sweep.yml +1 -1
  11. package/cdk/create-only/.github/workflows/ci.yml +2 -2
  12. package/cdk/create-only/.github/workflows/deploy.yml +3 -3
  13. package/cdk/package-lisa/package.lisa.json +1 -1
  14. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  15. package/dist/core/lisa-owned-hash-ledger.js +26 -0
  16. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  17. package/dist/core/lisa-owned-templates.d.ts +9 -2
  18. package/dist/core/lisa-owned-templates.d.ts.map +1 -1
  19. package/dist/core/lisa-owned-templates.js +13 -3
  20. package/dist/core/lisa-owned-templates.js.map +1 -1
  21. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  22. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  23. package/dist/core/upstream-evidence-manifest.js +59 -37
  24. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  25. package/expo/copy-overwrite/jest.setup.pre.js +15 -1
  26. package/expo/create-only/.github/workflows/ci.yml +3 -3
  27. package/expo/create-only/.github/workflows/deploy.yml +4 -4
  28. package/expo/create-only/.github/workflows/nightly-e2e-bypass-reaper.yml +1 -1
  29. package/expo/create-only/.github/workflows/playwright-e2e.yml +1 -1
  30. package/expo/create-only/eas.json +1 -1
  31. package/harper-fabric/copy-overwrite/.github/workflows/ci.yml +1 -1
  32. package/harper-fabric/create-only/.github/workflows/deploy.yml +3 -3
  33. package/harper-fabric/create-only/.github/workflows/zap-baseline.yml +1 -1
  34. package/harper-fabric/package-lisa/package.lisa.json +2 -2
  35. package/nestjs/create-only/.github/workflows/ci.yml +2 -2
  36. package/nestjs/create-only/.github/workflows/deploy.yml +5 -5
  37. package/package.json +6 -6
  38. package/phaser/copy-overwrite/.github/workflows/ci.yml +1 -1
  39. package/phaser/package-lisa/package.lisa.json +2 -2
  40. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  41. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  42. package/plugins/lisa/.codex-plugin/skills/lisa-parity-sentry-sdk-setup/SKILL.md +104 -0
  43. package/plugins/lisa/.codex-plugin/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -1
  44. package/plugins/lisa/skills/lisa-parity-sentry-sdk-setup/SKILL.md +104 -0
  45. package/plugins/lisa/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -1
  46. package/plugins/lisa-agy/plugin.json +1 -1
  47. package/plugins/lisa-agy/skills/lisa-parity-sentry-sdk-setup/SKILL.md +104 -0
  48. package/plugins/lisa-agy/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -1
  49. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  50. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  51. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  52. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  55. package/plugins/lisa-copilot/skills/lisa-parity-sentry-sdk-setup/SKILL.md +104 -0
  56. package/plugins/lisa-copilot/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -1
  57. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-cursor/skills/lisa-parity-sentry-sdk-setup/SKILL.md +104 -0
  59. package/plugins/lisa-cursor/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -1
  60. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  62. package/plugins/lisa-expo-agy/plugin.json +1 -1
  63. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  64. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  65. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  67. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  68. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  69. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  72. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  73. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  74. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  75. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  77. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  78. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  82. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  83. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  84. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  87. package/plugins/lisa-rails-agy/plugin.json +1 -1
  88. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  89. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  91. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  92. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  93. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  94. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  95. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  96. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  97. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  98. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  99. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  100. package/plugins/src/base/skills/lisa-parity-sentry-sdk-setup/SKILL.md +104 -0
  101. package/plugins/src/base/skills/lisa-setup-workstation/scripts/workstation.mjs +3 -1
  102. package/scripts/check-shell-guard-refusal-coverage.mjs +65 -7
  103. package/scripts/generate-lisa-owned-hash-ledger.mjs +3 -0
  104. package/scripts/lib/shell-guard-shard-runner.mjs +381 -0
  105. package/scripts/lib/shell-guard-shards.mjs +383 -0
  106. package/scripts/lib/shell-guard-terminal-reporter.mjs +89 -0
  107. package/scripts/two-channel-couplings.json +1 -1
  108. package/scripts/update-node-version.ts +52 -6
  109. package/typescript/copy-overwrite/.nvmrc +1 -1
  110. package/typescript/create-only/.github/workflows/ci.yml +1 -1
  111. package/typescript/create-only/.github/workflows/review-evidence.yml +1 -1
  112. package/typescript/create-only/.github/workflows/third-party-review-evidence.yml +1 -1
  113. package/typescript/package-lisa/package.lisa.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
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.73.8",
3
+ "version": "4.74.0",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "4.73.8",
3
+ "version": "4.74.0",
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.73.8",
3
+ "version": "4.74.0",
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.73.8",
3
+ "version": "4.74.0",
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"
@@ -84,6 +84,8 @@ Inspect the project before choosing an SDK. Read `package.json`
84
84
  - `pyproject.toml` / `requirements.txt`; `django`/`flask`/`fastapi` →
85
85
  **Python** (and which web framework)
86
86
  - A plain Node library/CLI → **Node**
87
+ - AWS Lambda handlers or a Serverless/SAM/CDK function runtime → inspect the
88
+ function's actual runtime and wrapper before choosing **Node/Lambda**.
87
89
 
88
90
  If the runtime is genuinely ambiguous, ask which app to instrument rather than
89
91
  guessing. Respect the project's package manager (bun/npm/pnpm/yarn — match the
@@ -98,6 +100,7 @@ Use the project's package manager. Examples (swap `bun add` for your manager):
98
100
  | React (browser) | `@sentry/react` |
99
101
  | Next.js | `@sentry/nextjs` |
100
102
  | Node / Express / Fastify | `@sentry/node` (+ `@sentry/profiling-node` for profiling) |
103
+ | AWS Lambda | `@sentry/aws-serverless` for a compatible Lambda wrapper, or `@sentry/node` for an unwrapped async handler |
101
104
  | NestJS | `@sentry/nestjs` (+ `@sentry/node`) |
102
105
  | React Native / Expo | `@sentry/react-native` |
103
106
  | Vue | `@sentry/vue` |
@@ -148,6 +151,107 @@ Sentry.init({
148
151
 
149
152
  Then, after routes are defined: `Sentry.setupExpressErrorHandler(app);`
150
153
 
154
+ ### Node24 Lambda completion
155
+
156
+ Review the actual function runtime and installed SDK before migrating. Node24
157
+ LTS is Lisa's default for new TypeScript hosts; an existing host's explicit
158
+ engine and create-only workflows remain host-owned. On AWS Lambda `nodejs24.x`,
159
+ callback-style handlers and legacy context completion APIs, including
160
+ `callbackWaitsForEmptyEventLoop`, are removed. Do not assign those properties,
161
+ including to frozen/non-extensible context objects. Supported async handlers,
162
+ synchronous returns and response streaming are distinct forms; follow the
163
+ [AWS handler contract](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html).
164
+
165
+ Earlier non-streaming async handlers already returned without waiting for
166
+ unresolved background promises. Node24 aligns streaming completion with that
167
+ behavior; await work that must finish before returning or ending the stream.
168
+ Do not claim all Node20/22 async handlers drained arbitrary background work.
169
+ For streaming, flush at the appropriate point before `responseStream.end()` or
170
+ inside the awaited streaming pipeline, rather than after the stream is ended.
171
+ [AWS's Node24 migration explanation](https://aws.amazon.com/blogs/compute/node-js-24-runtime-now-available-in-aws-lambda/)
172
+ is the runtime authority; ordinary local Node process behavior is not deployed
173
+ Lambda evidence.
174
+
175
+ For an **unwrapped async** scheduled, queue or Cognito handler, initialize Sentry
176
+ once at module startup with the DSN from the environment. Await a finite positive
177
+ flush budget on both success and original-error paths. A false flush result or
178
+ rejection must not turn successful queue work into a retry or replace its real
179
+ error. Keep diagnostics local and non-throwing, and preserve the client for warm
180
+ invocations: `close()` disables it. The following helper wraps the host's existing
181
+ business operation; it neither mutates context nor adds a Lambda callback.
182
+
183
+ <!-- lisa-node24-unwrapped-example:start -->
184
+ ```ts
185
+ import * as Sentry from "@sentry/node";
186
+
187
+ // Initialize early, once outside the handler, with DSN from the environment.
188
+ function reportFlushProblem(message: string): void {
189
+ try {
190
+ console.warn(message);
191
+ } catch {
192
+ // Telemetry diagnostics must preserve the business outcome too.
193
+ }
194
+ }
195
+
196
+ export async function withSentryFlush<T>(
197
+ work: () => Promise<T>,
198
+ timeoutMs = 2000
199
+ ): Promise<T> {
200
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
201
+ throw new RangeError("Choose a finite positive Sentry flush budget");
202
+ }
203
+ try {
204
+ return await work();
205
+ } catch (originalError) {
206
+ try {
207
+ Sentry.captureException(originalError);
208
+ } catch {
209
+ // Preserve the original handler error even if capture fails.
210
+ }
211
+ throw originalError;
212
+ } finally {
213
+ try {
214
+ if (!(await Sentry.flush(timeoutMs))) {
215
+ reportFlushProblem("Sentry flush did not finish in time");
216
+ }
217
+ } catch {
218
+ reportFlushProblem("Sentry flush rejected");
219
+ }
220
+ }
221
+ }
222
+ ```
223
+ <!-- lisa-node24-unwrapped-example:end -->
224
+
225
+ In the existing async handler, return
226
+ `withSentryFlush(() => performBusinessWork(event, context))`; use the host's
227
+ actual business operation and preserve its return/error contract. Select a
228
+ positive budget that fits remaining invocation time with a safety margin.
229
+ Do not omit the timeout or use zero as a finite cap. The SDK's timeout argument
230
+ does not cancel every custom transport or guarantee completion before Lambda's
231
+ hard timeout, and a drained local queue does not prove tenant ingestion.
232
+ [Sentry API semantics](https://docs.sentry.io/platforms/javascript/guides/aws-lambda/configuration/apis.md)
233
+ describe `flush()` and `close()`.
234
+
235
+ For a **compatible `Sentry.wrapHandler`**, its documented default flush is up
236
+ to2000ms, configurable through `flushTimeout`; avoid a redundant manual flush
237
+ when that wrapper already handles completion. Check the installed version's
238
+ context behavior, too: `@sentry/aws-serverless`11.6.0 unconditionally assigns
239
+ `context.callbackWaitsForEmptyEventLoop` before invoking the business handler.
240
+ It throws on a non-extensible context lacking that removed property. Changing
241
+ the option does not remove the assignment. Use the unwrapped form when this
242
+ incompatibility applies; do not clone/unfreeze context or pre-add an obsolete
243
+ property to claim compatibility. See the [wrapper documentation](https://docs.sentry.io/platforms/javascript/guides/aws-lambda/configuration/lambda-wrapper.md)
244
+ and [versioned implementation](https://github.com/getsentry/sentry-javascript/blob/11.6.0/packages/aws-serverless/src/sdk.ts).
245
+
246
+ Treat Node types and optional native profiling as migration checks. Examples
247
+ using `Array.at` need an ES2022-or-later TypeScript `lib`; keep a host's business
248
+ compiler target deliberate. Confirm optional profiling prebuilds against the
249
+ actual Node ABI (Node24 uses137) only when profiling is in use; do not install an
250
+ unused profiling package. Verify the helper with the real installed SDK and
251
+ local transport, including success/error, timeout/false, rejected flush and a
252
+ second warm invocation. Label local observations honestly; actual Lambda
253
+ deployment and Sentry event ingestion require their own provider proof.
254
+
151
255
  **NestJS** — import `./instrument` first in `main.ts`, then add Sentry's module:
152
256
 
153
257
  ```ts
@@ -63,7 +63,9 @@ import {
63
63
  export function locate(name, exec = boundedChildOutput) {
64
64
  try {
65
65
  return String(
66
- exec("command", ["-v", name], { encoding: "utf8", shell: true })
66
+ exec("sh", ["-c", 'command -v -- "$1"', "lisa-locate", name], {
67
+ encoding: "utf8",
68
+ })
67
69
  ).trim();
68
70
  } catch {
69
71
  // probe-direction: fail-closed — null means "not proven present", and the
@@ -35,9 +35,17 @@
35
35
  * --trace-out FILE
36
36
  * also write the judged trace to FILE, so a later step in the
37
37
  * same job can read what this run observed. Never commit it.
38
+ * --collect-only --shard I/3 --trace-out NEW_DIRECTORY/trace.jsonl
39
+ * collect one complete native Actions shard without judging
40
+ * its individual trace. All canonical candidates are supplied.
41
+ * --merge-traces DIRECTORY --trace-out FILE
42
+ * validate all three current run/attempt shard receipts, then
43
+ * apply the original judge once to their combined trace.
44
+ * A new Actions attempt must reproduce all three shards.
38
45
  *
39
46
  * Exit codes (mirroring the sibling check-* scripts):
40
- * 0 — every guard the run drove was observed refusing and allowing.
47
+ * 0 — the judgment passed, or --collect-only retained a complete eligible
48
+ * shard without judging its individual trace.
41
49
  * 1 — >=1 finding.
42
50
  * 2 — operational error: unknown flag, vitest could not run, or ZERO guards
43
51
  * observed.
@@ -59,9 +67,15 @@ import {
59
67
  parseTrace,
60
68
  tracerIndex,
61
69
  } from "./lib/shell-guard-refusal-coverage.mjs";
70
+ import {
71
+ collectShard,
72
+ mergeCollected,
73
+ } from "./lib/shell-guard-shard-runner.mjs";
62
74
 
63
75
  /** The flag naming a file the produced trace should also be written to. */
64
76
  const TRACE_OUT_FLAG = "--trace-out";
77
+ /** Collection receipts to combine before the original judgment. */
78
+ const MERGE_TRACES_FLAG = "--merge-traces";
65
79
 
66
80
  /** Wall-clock ceiling for the traced vitest run. */
67
81
  const RUN_TIMEOUT_MS = 45 * 60_000;
@@ -233,8 +247,20 @@ function keepTrace(root, args, trace) {
233
247
  */
234
248
  export function main() {
235
249
  const args = process.argv.slice(2);
236
- const known = new Set(["--json", "--trace", TRACE_OUT_FLAG]);
237
- const valueFlags = new Set(["--trace", TRACE_OUT_FLAG]);
250
+ const known = new Set([
251
+ "--json",
252
+ "--trace",
253
+ TRACE_OUT_FLAG,
254
+ "--collect-only",
255
+ "--shard",
256
+ MERGE_TRACES_FLAG,
257
+ ]);
258
+ const valueFlags = new Set([
259
+ "--trace",
260
+ TRACE_OUT_FLAG,
261
+ "--shard",
262
+ MERGE_TRACES_FLAG,
263
+ ]);
238
264
  const unknown = args.find(
239
265
  (arg, at) =>
240
266
  arg.startsWith("--") &&
@@ -249,13 +275,45 @@ export function main() {
249
275
  return;
250
276
  }
251
277
  const root = process.cwd();
278
+ if (args.includes("--collect-only")) {
279
+ try {
280
+ collectShard(root, candidateSuites, args);
281
+ } catch (error) {
282
+ console.error(`check:shell-guard-refusal-coverage: ${String(error)}`);
283
+ process.exitCode = 2;
284
+ }
285
+ return;
286
+ }
287
+ if (args.includes("--shard")) {
288
+ console.error(
289
+ "check:shell-guard-refusal-coverage: --shard requires --collect-only"
290
+ );
291
+ process.exitCode = 2;
292
+ return;
293
+ }
252
294
  const population = guardPopulation(root);
253
295
  const at = args.indexOf("--trace");
254
296
  const supplied = at === -1 ? undefined : args[at + 1];
255
- const produced =
256
- supplied === undefined
257
- ? produceTrace(root, population)
258
- : { trace: readOrEmpty(root, supplied), suites: 0, ok: true, detail: "" };
297
+ let produced;
298
+ if (args.includes(MERGE_TRACES_FLAG)) {
299
+ try {
300
+ produced = mergeCollected(root, candidateSuites, args);
301
+ } catch (error) {
302
+ console.error(`check:shell-guard-refusal-coverage: ${String(error)}`);
303
+ process.exitCode = 2;
304
+ return;
305
+ }
306
+ } else {
307
+ produced =
308
+ supplied === undefined
309
+ ? produceTrace(root, population)
310
+ : {
311
+ trace: readOrEmpty(root, supplied),
312
+ suites: 0,
313
+ ok: true,
314
+ detail: "",
315
+ };
316
+ }
259
317
  if (!produced.ok) {
260
318
  console.error(`check:shell-guard-refusal-coverage: ${produced.detail}`);
261
319
  process.exitCode = 2;
@@ -160,6 +160,9 @@ function git(root, args) {
160
160
  */
161
161
  export function isLisaOwned(destination) {
162
162
  return (
163
+ // Exact runtime-policy destination only, mirrored by the runtime predicate.
164
+ // Enrol historical hashes too so custom/newer host content stays protected.
165
+ destination === ".nvmrc" ||
163
166
  destination.startsWith(ENFORCEMENT_TREE) ||
164
167
  destination
165
168
  .split("/")