@codyswann/lisa 4.4.0 → 4.4.2

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 (75) hide show
  1. package/dist/codex/mcp-installer.d.ts.map +1 -1
  2. package/dist/codex/mcp-installer.js +55 -10
  3. package/dist/codex/mcp-installer.js.map +1 -1
  4. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  5. package/dist/core/upstream-evidence-manifest.js +15 -13
  6. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  7. package/package.json +1 -1
  8. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  9. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  10. package/plugins/lisa/.codex-plugin/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +130 -26
  11. package/plugins/lisa/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +130 -26
  12. package/plugins/lisa-agy/plugin.json +1 -1
  13. package/plugins/lisa-agy/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +130 -26
  14. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  15. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  16. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  17. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  18. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  19. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  20. package/plugins/lisa-copilot/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +130 -26
  21. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-cursor/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +130 -26
  23. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  25. package/plugins/lisa-expo-agy/plugin.json +1 -1
  26. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  27. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  29. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  30. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  31. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  33. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  35. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  36. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  37. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  38. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  40. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  41. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  42. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  43. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  45. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  46. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  50. package/plugins/lisa-rails-agy/plugin.json +1 -1
  51. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  55. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  56. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  60. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  61. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  63. package/plugins/src/base/skills/lisa-secrets-access/scripts/materialize-secrets.mjs +130 -26
  64. package/scripts/check-delivery-deletion-conflicts.mjs +2 -2
  65. package/scripts/check-derived-artifacts.mjs +24 -5
  66. package/scripts/check-orphan-test-processes.mjs +2 -2
  67. package/scripts/check-security-floors.mjs +20 -9
  68. package/scripts/check-template-workflow-refs.mjs +23 -8
  69. package/scripts/check-workflow-package-paths.mjs +12 -8
  70. package/scripts/generate-lisa-owned-hash-ledger.mjs +12 -4
  71. package/scripts/generate-upstream-evidence-manifest.mjs +4 -4
  72. package/scripts/verify-health-agentic-built.mjs +4 -3
  73. package/scripts/verify-health-consumer-built.mjs +3 -2
  74. package/scripts/verify-health-contract-built.mjs +3 -2
  75. package/scripts/verify-health-deterministic-built.mjs +5 -4
@@ -77,7 +77,6 @@
77
77
  *
78
78
  * @module scripts/check-workflow-package-paths
79
79
  */
80
- import { execFileSync } from "node:child_process";
81
80
  import {
82
81
  existsSync,
83
82
  mkdirSync,
@@ -89,6 +88,7 @@ import { mkdtempSync } from "node:fs";
89
88
  import { tmpdir } from "node:os";
90
89
  import path from "node:path";
91
90
 
91
+ import { boundedExecFileSync } from "./lib/bounded-spawn.mjs";
92
92
  import { invokedAsScript } from "./lib/invoked-as-script.mjs";
93
93
 
94
94
  /** The package whose released layout a workflow may make claims about. */
@@ -179,7 +179,7 @@ function parseArgs(argv) {
179
179
  * @returns {readonly string[]} Repo-relative workflow paths
180
180
  */
181
181
  function trackedWorkflows(root) {
182
- const output = execFileSync(
182
+ const output = boundedExecFileSync(
183
183
  "git",
184
184
  ["-C", root, "ls-files", ".github/workflows"],
185
185
  { encoding: "utf8" }
@@ -285,7 +285,7 @@ export function collectClaims(root) {
285
285
  */
286
286
  function publishedVersions() {
287
287
  const versions = JSON.parse(
288
- execFileSync("npm", ["view", PACKAGE_NAME, "versions", "--json"], {
288
+ boundedExecFileSync("npm", ["view", PACKAGE_NAME, "versions", "--json"], {
289
289
  encoding: "utf8",
290
290
  stdio: ["ignore", "pipe", "pipe"],
291
291
  maxBuffer: 16 * 1024 * 1024,
@@ -357,7 +357,7 @@ function fetchReleaseListings(chosen, cacheDir) {
357
357
  continue;
358
358
  }
359
359
  const staging = mkdtempSync(path.join(tmpdir(), "lisa-release-"));
360
- execFileSync(
360
+ boundedExecFileSync(
361
361
  "npm",
362
362
  ["pack", `${PACKAGE_NAME}@${version}`, "--pack-destination", staging],
363
363
  { stdio: ["ignore", "pipe", "pipe"] }
@@ -366,10 +366,14 @@ function fetchReleaseListings(chosen, cacheDir) {
366
366
  if (tarball === undefined) {
367
367
  throw new Error(`npm pack produced no tarball for ${version}`);
368
368
  }
369
- const entries = execFileSync("tar", ["-tzf", path.join(staging, tarball)], {
370
- encoding: "utf8",
371
- maxBuffer: 64 * 1024 * 1024,
372
- })
369
+ const entries = boundedExecFileSync(
370
+ "tar",
371
+ ["-tzf", path.join(staging, tarball)],
372
+ {
373
+ encoding: "utf8",
374
+ maxBuffer: 64 * 1024 * 1024,
375
+ }
376
+ )
373
377
  .split("\n")
374
378
  .filter(Boolean);
375
379
  listings[version] = entries;
@@ -19,11 +19,12 @@
19
19
  * legitimately stale file as host-modified and stop refreshing it — failing
20
20
  * safe, but permanently.
21
21
  */
22
- import { execFileSync } from "node:child_process";
23
22
  import { createHash } from "node:crypto";
24
23
  import { readFileSync, writeFileSync } from "node:fs";
25
24
  import path from "node:path";
26
25
 
26
+ import { boundedExecFileSync, isChildTimeout } from "./lib/bounded-spawn.mjs";
27
+
27
28
  const repoRoot = path.resolve(import.meta.dirname, "..");
28
29
  const outputPath = path.join(repoRoot, "src/core/lisa-owned-hash-ledger.ts");
29
30
  const COPY_OVERWRITE = "copy-overwrite";
@@ -35,18 +36,25 @@ const ENFORCEMENT_TREE = "scripts/";
35
36
  *
36
37
  * Blobs are read as `binary` so arbitrary bytes survive the round trip into the
37
38
  * Buffer that gets hashed; decoding as UTF-8 would corrupt any non-text file.
39
+ * A KILLED child re-raises. Every caller reads this as content, and an empty
40
+ * string is a perfectly well-formed answer meaning "no files" — so a timeout
41
+ * on the `ls-files` call would build a ledger that vouches for NOTHING and
42
+ * report it as a complete one. A ledger's whole job is to vouch for bytes; one
43
+ * assembled from silence is worse than none, because it looks authoritative.
38
44
  * @param {readonly string[]} args - Arguments passed to git
39
- * @returns {string} Command stdout, or an empty string when git fails
45
+ * @returns {string} Command stdout, or an empty string when git said nothing
46
+ * @throws {Error} When the child was killed at its deadline
40
47
  */
41
48
  function git(args) {
42
49
  try {
43
- return execFileSync("git", args, {
50
+ return boundedExecFileSync("git", args, {
44
51
  cwd: repoRoot,
45
52
  encoding: "buffer",
46
53
  maxBuffer: 64 * 1024 * 1024,
47
54
  stdio: ["ignore", "pipe", "ignore"],
48
55
  }).toString("binary");
49
- } catch {
56
+ } catch (error) {
57
+ if (isChildTimeout(error)) throw error;
50
58
  return "";
51
59
  }
52
60
  }
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  /** Generate the exact hash-pinned allowlist for public upstream evidence. */
3
- import { execFileSync } from "node:child_process";
4
3
  import { createHash } from "node:crypto";
5
4
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
6
5
  import path from "node:path";
7
6
 
7
+ import { boundedExecFileSync } from "./lib/bounded-spawn.mjs";
8
8
  import {
9
9
  describeStaleManifest,
10
10
  diagnoseStaleManifest,
@@ -86,7 +86,7 @@ function repositoryPath(url) {
86
86
  // comparison is by path: `url.<base>.insteadOf` rewrites what `git remote
87
87
  // get-url` returns, so it answers "how do I reach this" rather than "what is
88
88
  // this". Falls back to the resolved URL only if no value is configured.
89
- const originUrl = execFileSync(
89
+ const originUrl = boundedExecFileSync(
90
90
  "git",
91
91
  ["config", "--get", "remote.origin.url"],
92
92
  { cwd: repoRoot, encoding: "utf8" }
@@ -100,7 +100,7 @@ if (repositoryPath(originUrl) !== canonicalRepository.toLowerCase()) {
100
100
  );
101
101
  }
102
102
 
103
- const tracked = execFileSync("git", ["ls-files", "-z"], {
103
+ const tracked = boundedExecFileSync("git", ["ls-files", "-z"], {
104
104
  cwd: repoRoot,
105
105
  encoding: "utf8",
106
106
  })
@@ -135,7 +135,7 @@ const existingPublicCommits = [
135
135
  .filter(Boolean);
136
136
  const refreshPublicCommits = process.argv.includes("--refresh-public-commits");
137
137
  const discoveredPublicCommits = refreshPublicCommits
138
- ? execFileSync("git", ["rev-list", "--remotes=origin"], {
138
+ ? boundedExecFileSync("git", ["rev-list", "--remotes=origin"], {
139
139
  cwd: repoRoot,
140
140
  encoding: "utf8",
141
141
  })
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /** Empirical proof for the shipped optional agentic Health composition API. */
3
3
  import assert from "node:assert/strict";
4
- import { execFileSync } from "node:child_process";
5
4
  import { createHash } from "node:crypto";
6
5
  import {
7
6
  lstat,
@@ -17,6 +16,8 @@ import {
17
16
  import { tmpdir } from "node:os";
18
17
  import path from "node:path";
19
18
 
19
+ import { boundedExecFileSync } from "./lib/bounded-spawn.mjs";
20
+
20
21
  // Literals named once — each was repeated enough times that a typo in one
21
22
  // copy would diverge silently.
22
23
  const TEMPLATES_MANAGED = "templates.managed";
@@ -62,14 +63,14 @@ const root = process.cwd();
62
63
  const workspace = await mkdtemp(path.join(tmpdir(), "lisa-health-agentic-"));
63
64
  const project = path.join(workspace, "host");
64
65
  const isolatedBin = path.join(workspace, "bin");
65
- const gitExecutable = execFileSync("which", ["git"], {
66
+ const gitExecutable = boundedExecFileSync("which", ["git"], {
66
67
  encoding: "utf8",
67
68
  }).trim();
68
69
  const healthFile = path.join(project, ".lisa", "health", "latest.json");
69
70
  const startedAt = Date.now();
70
71
 
71
72
  const run = (executable, argv, options = {}) =>
72
- execFileSync(executable, argv, {
73
+ boundedExecFileSync(executable, argv, {
73
74
  cwd: project,
74
75
  encoding: "utf8",
75
76
  stdio: ["ignore", "pipe", "pipe"],
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /** Built-package proof for the real two-phase Health CLI consumer. */
3
3
  import assert from "node:assert/strict";
4
- import { execFileSync } from "node:child_process";
5
4
  import {
6
5
  lstat,
7
6
  mkdir,
@@ -14,6 +13,8 @@ import {
14
13
  import { tmpdir } from "node:os";
15
14
  import path from "node:path";
16
15
 
16
+ import { boundedExecFileSync } from "./lib/bounded-spawn.mjs";
17
+
17
18
  // Literals named once — each was repeated enough times that a typo in one
18
19
  // copy would diverge silently.
19
20
  const LATEST_JSON = "latest.json";
@@ -53,7 +54,7 @@ async function createProject(name) {
53
54
 
54
55
  /** Run the compiled CLI and capture its exact standard-output bytes. */
55
56
  function runCli(project, argv, input) {
56
- return execFileSync(
57
+ return boundedExecFileSync(
57
58
  process.execPath,
58
59
  [cli, "--no-update-check", "health", ...argv, project],
59
60
  {
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  /** Empirical proof for the shipped Health v1 contract and real built CLI. */
3
3
  import assert from "node:assert/strict";
4
- import { execFileSync } from "node:child_process";
5
4
  import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
6
5
  import { tmpdir } from "node:os";
7
6
  import path from "node:path";
8
7
 
8
+ import { boundedExecFileSync } from "./lib/bounded-spawn.mjs";
9
+
9
10
  let assertions = 0;
10
11
  const check = (condition, message) => {
11
12
  assertions += 1;
@@ -23,7 +24,7 @@ try {
23
24
  path.join(project, ".lisa.config.json"),
24
25
  `${JSON.stringify({ tracker: "github", github: { org: "acme", repo: "app" } }, null, 2)}\n`
25
26
  );
26
- execFileSync(
27
+ boundedExecFileSync(
27
28
  process.execPath,
28
29
  [path.join(root, "dist/index.js"), "sync", project, "--json"],
29
30
  {
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /** Empirical proof for the shipped deterministic Health fast path. */
3
3
  import assert from "node:assert/strict";
4
- import { execFileSync } from "node:child_process";
5
4
  import { createHash } from "node:crypto";
6
5
  import {
7
6
  chmod,
@@ -18,6 +17,8 @@ import {
18
17
  import { tmpdir } from "node:os";
19
18
  import path from "node:path";
20
19
 
20
+ import { boundedExecFileSync } from "./lib/bounded-spawn.mjs";
21
+
21
22
  // Literals named once — each was repeated enough times that a typo in one
22
23
  // copy would diverge silently.
23
24
  const PACKAGE_JSON = "package.json";
@@ -40,14 +41,14 @@ const root = process.cwd();
40
41
  const workspace = await mkdtemp(path.join(tmpdir(), "lisa-health-fast-path-"));
41
42
  const project = path.join(workspace, "host");
42
43
  const isolatedBin = path.join(workspace, "bin");
43
- const gitExecutable = execFileSync("which", ["git"], {
44
+ const gitExecutable = boundedExecFileSync("which", ["git"], {
44
45
  encoding: "utf8",
45
46
  }).trim();
46
47
  const healthFile = path.join(project, ".lisa", "health", "latest.json");
47
48
  const startedAt = Date.now();
48
49
 
49
50
  const run = (executable, argv, options = {}) =>
50
- execFileSync(executable, argv, {
51
+ boundedExecFileSync(executable, argv, {
51
52
  cwd: project,
52
53
  encoding: "utf8",
53
54
  stdio: ["ignore", "pipe", "pipe"],
@@ -466,7 +467,7 @@ try {
466
467
  path.join(unsafeProject, LISA_CONFIG_JSON),
467
468
  '{"tracker":"github","harness":"codex"}\n'
468
469
  );
469
- execFileSync("mkfifo", [path.join(unsafeProject, PACKAGE_JSON)]);
470
+ boundedExecFileSync("mkfifo", [path.join(unsafeProject, PACKAGE_JSON)]);
470
471
  const unsafeStarted = Date.now();
471
472
  const unsafe = await health.runDeterministicHealth(unsafeProject, {
472
473
  lisaRoot: root,