@codyswann/lisa 4.72.6 → 4.73.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 (93) hide show
  1. package/all/copy-overwrite/scripts/lib/automation-provenance-contract.mjs +19 -0
  2. package/all/copy-overwrite/scripts/lib/automation-provenance-local.mjs +4 -2
  3. package/all/copy-overwrite/scripts/lib/history-secret-evidence-shape.mjs +398 -6
  4. package/all/copy-overwrite/scripts/lib/history-secret-evidence.mjs +175 -7
  5. package/all/copy-overwrite/scripts/lib/npm-update-cancel-origin.mjs +7 -1
  6. package/all/copy-overwrite/scripts/lib/npm-update-contract.mjs +11 -66
  7. package/all/copy-overwrite/scripts/lib/npm-update-gate.mjs +3 -0
  8. package/all/copy-overwrite/scripts/lib/npm-update-helper-inventory.mjs +10 -0
  9. package/all/copy-overwrite/scripts/lib/npm-update-hosted-gate.mjs +162 -121
  10. package/all/copy-overwrite/scripts/lib/npm-update-hosted-hook.mjs +8 -0
  11. package/all/copy-overwrite/scripts/lib/npm-update-hosted-scope.mjs +177 -0
  12. package/all/copy-overwrite/scripts/lib/npm-update-policy.mjs +73 -0
  13. package/all/copy-overwrite/scripts/lib/npm-update-publish.mjs +1 -0
  14. package/all/copy-overwrite/scripts/lib/npm-update-rails-mysql-daemon.mjs +227 -0
  15. package/all/copy-overwrite/scripts/lib/npm-update-rails-mysql-resource.mjs +176 -0
  16. package/all/copy-overwrite/scripts/lib/npm-update-rails-mysql-storage.mjs +201 -0
  17. package/all/copy-overwrite/scripts/lib/npm-update-rails-mysql.mjs +220 -0
  18. package/all/copy-overwrite/scripts/lib/npm-update-rails-runtime-contract.mjs +75 -0
  19. package/all/copy-overwrite/scripts/lib/npm-update-rails-tool-downloads.mjs +187 -0
  20. package/all/copy-overwrite/scripts/lib/npm-update-rails-tool-identity.mjs +288 -0
  21. package/all/copy-overwrite/scripts/lib/npm-update-rails-tools.mjs +292 -0
  22. package/all/copy-overwrite/scripts/lisa-automation-provenance.mjs +3 -0
  23. package/all/copy-overwrite/scripts/lisa-hooks/parity-safety-net.sh +1 -1
  24. package/all/copy-overwrite/scripts/lisa-scratch-run.sh +7 -4
  25. package/all/copy-overwrite/scripts/npm-updater-helper-graph.json +148 -20
  26. package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
  27. package/dist/core/lisa-owned-hash-ledger.js +126 -0
  28. package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
  29. package/dist/core/lisa.d.ts.map +1 -1
  30. package/dist/core/lisa.js +2 -1
  31. package/dist/core/lisa.js.map +1 -1
  32. package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
  33. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  34. package/dist/core/upstream-evidence-manifest.js +79 -17
  35. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  36. package/dist/opencode/plugin-templates/parity-safety-net.sh +1 -1
  37. package/package.json +4 -4
  38. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  39. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  40. package/plugins/lisa/hooks/parity-safety-net.sh +1 -1
  41. package/plugins/lisa-agy/hooks/parity-safety-net.sh +1 -1
  42. package/plugins/lisa-agy/plugin.json +1 -1
  43. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  44. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  45. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  46. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  47. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  48. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-copilot/hooks/parity-safety-net.sh +1 -1
  50. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  51. package/plugins/lisa-cursor/hooks/parity-safety-net.sh +1 -1
  52. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  54. package/plugins/lisa-expo-agy/plugin.json +1 -1
  55. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  57. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  58. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  59. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  60. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  64. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  65. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  69. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  70. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  74. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  75. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  79. package/plugins/lisa-rails-agy/plugin.json +1 -1
  80. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  84. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  85. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  88. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  89. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  90. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  91. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  92. package/plugins/src/base/hooks/parity-safety-net.sh +1 -1
  93. package/scripts/two-channel-couplings.json +1 -1
@@ -9,12 +9,15 @@ import {
9
9
  HistorySecretError,
10
10
  } from "./history-secret-git.mjs";
11
11
  import {
12
+ coordinateManifest,
13
+ coordinateMaps,
12
14
  evidenceMaps,
13
- narrativeSpan,
15
+ paragraphNarrativeSpan,
14
16
  safeSourcePath,
15
17
  } from "./history-secret-evidence-shape.mjs";
16
18
  const BUDGET = 64 * 1024 * 1024;
17
19
  const NO_REPLACEMENTS = "--no-replace-objects";
20
+ const LITERAL_PATHSPECS = "--literal-pathspecs";
18
21
  const digest = bytes => createHash("sha256").update(bytes).digest("hex");
19
22
  const options = cwd => ({
20
23
  cwd,
@@ -27,7 +30,7 @@ const options = cwd => ({
27
30
  const readBlob = (file, commit, cwd, state) => {
28
31
  if (!safeSourcePath(file)) return null;
29
32
  const entries = gitRead(
30
- ["--literal-pathspecs", "ls-tree", "-z", commit, "--", file],
33
+ [LITERAL_PATHSPECS, "ls-tree", "-z", commit, "--", file],
31
34
  cwd
32
35
  )
33
36
  .split("\0")
@@ -116,7 +119,7 @@ const sourceVersions = (file, row, cwd, commits, cache) => {
116
119
  for (let offset = 0; offset < commits.length; offset += 100) {
117
120
  const list = gitRead(
118
121
  [
119
- "--literal-pathspecs",
122
+ LITERAL_PATHSPECS,
120
123
  "log",
121
124
  "--no-walk=unsorted",
122
125
  "--format=%H",
@@ -224,12 +227,156 @@ const verifiedMap = (map, row, cwd, commits, heads, blob, versions) => {
224
227
  return map.spans;
225
228
  };
226
229
 
230
+ const coordinateKey = origin =>
231
+ JSON.stringify([
232
+ origin.commit,
233
+ origin.blob,
234
+ origin.path,
235
+ origin.format,
236
+ origin.map_pointer,
237
+ ...origin.value_span,
238
+ ]);
239
+ const blobIdentity = (bytes, width) =>
240
+ createHash(width === 40 ? "sha1" : "sha256")
241
+ .update(`blob ${bytes.length}\0`)
242
+ .update(bytes)
243
+ .digest("hex");
244
+
245
+ /** Discover only sidecar snapshots in the original selected commit set. */
246
+ const selectedCoordinates = (cwd, commits, blob) => {
247
+ const path = ".lisa/history-secret-evidence.json";
248
+ const candidates = new Set();
249
+ for (let offset = 0; offset < commits.length; offset += 100) {
250
+ const list = gitRead(
251
+ [
252
+ LITERAL_PATHSPECS,
253
+ "log",
254
+ "--no-walk=unsorted",
255
+ "--format=%H",
256
+ ...commits.slice(offset, offset + 100),
257
+ "--",
258
+ path,
259
+ ],
260
+ cwd
261
+ );
262
+ for (const commit of list.split("\n").filter(Boolean)) {
263
+ if (!commits.includes(commit))
264
+ throw new HistorySecretError(
265
+ "Evidence selection is invalid; safety is unproved."
266
+ );
267
+ candidates.add(commit);
268
+ }
269
+ }
270
+ if (!candidates.size) return { present: false, entries: new Map() };
271
+ const snapshots = new Map();
272
+ for (const commit of candidates) {
273
+ const exists = gitRead(
274
+ [LITERAL_PATHSPECS, "ls-tree", "--name-only", commit, "--", path],
275
+ cwd
276
+ );
277
+ if (!exists) continue;
278
+ const bytes = blob(path, commit);
279
+ if (bytes === null) return { present: true, entries: null };
280
+ snapshots.set(blobIdentity(bytes, commit.length), bytes);
281
+ }
282
+ if (!snapshots.size) return { present: false, entries: new Map() };
283
+ if (snapshots.size !== 1) return { present: true, entries: null };
284
+ const entries = coordinateManifest(
285
+ [...snapshots.values()][0],
286
+ commits[0].length
287
+ );
288
+ if (entries === null) return { present: true, entries: null };
289
+ const indexed = new Map();
290
+ const spans = new Map();
291
+ const documents = new Set();
292
+ for (const entry of entries) {
293
+ if (!commits.includes(entry.origin.commit))
294
+ return { present: true, entries: null };
295
+ const key = coordinateKey(entry.origin);
296
+ const file = JSON.stringify([
297
+ entry.origin.commit,
298
+ entry.origin.blob,
299
+ entry.origin.path,
300
+ ]);
301
+ const intervals = spans.get(file) ?? [];
302
+ const [start, end] = entry.origin.value_span;
303
+ if (indexed.has(key) || intervals.some(([a, b]) => start < b && end > a))
304
+ return { present: true, entries: null };
305
+ intervals.push([start, end]);
306
+ spans.set(file, intervals);
307
+ indexed.set(key, entry.preimage);
308
+ documents.add(JSON.stringify([entry.origin.commit, entry.origin.path]));
309
+ }
310
+ return { present: true, entries: indexed, documents };
311
+ };
312
+
313
+ /** Explicit and typed ancestor claims require independent original commit verification. */
314
+ const coordinateRevision = (map, preimage, row, cwd) => {
315
+ const hasTyped = Object.hasOwn(map.value, "commit_parent");
316
+ const typed = map.value.commit_parent;
317
+ if (
318
+ hasTyped &&
319
+ Object.hasOwn(preimage, "commit") &&
320
+ typed !== preimage.commit
321
+ )
322
+ return null;
323
+ if (!hasTyped && !Object.hasOwn(preimage, "commit")) return row.Commit;
324
+ const revision = hasTyped ? typed : preimage.commit;
325
+ return revisionFor({ value: { source_revision: revision } }, row, cwd);
326
+ };
327
+
328
+ /** Every literal, including unflagged siblings, needs its own exact coordinate and preimage. */
329
+ const verifiedCoordinateMap = (
330
+ map,
331
+ row,
332
+ bytes,
333
+ coordinates,
334
+ cwd,
335
+ selected,
336
+ blob
337
+ ) => {
338
+ if (coordinates === null) return [];
339
+ const identity = blobIdentity(bytes, row.Commit.length);
340
+ for (const span of map.spans) {
341
+ const preimage = coordinates.get(
342
+ coordinateKey({
343
+ commit: row.Commit,
344
+ blob: identity,
345
+ path: row.File,
346
+ format: map.format,
347
+ map_pointer: map.pointer,
348
+ value_span: [span.start, span.end],
349
+ })
350
+ );
351
+ if (
352
+ !preimage ||
353
+ bytes.subarray(span.start, span.end).toString("ascii") !== span.hash
354
+ )
355
+ return [];
356
+ let original;
357
+ if (map.kind === "proof") {
358
+ if (preimage.kind !== "archive" || !selected.has(preimage.commit))
359
+ return [];
360
+ original = blob(preimage.path, preimage.commit);
361
+ } else {
362
+ if (preimage.kind !== "source") return [];
363
+ const revision = coordinateRevision(map, preimage, row, cwd);
364
+ if (revision === null) return [];
365
+ original = blob(span.file, revision);
366
+ }
367
+ if (original === null || digest(original) !== span.hash) return [];
368
+ }
369
+ return map.spans;
370
+ };
371
+
227
372
  /** Clear a finding only after syntax, original span and independently verified bytes agree. */
228
373
  export const classifyEvidence = (cwd, commits, heads) => {
229
374
  const state = { remaining: BUDGET, blobs: new Map() };
230
375
  const refs = new Map();
231
376
  const maps = new Map();
232
377
  const versions = new Map();
378
+ const selected = new Set(commits);
379
+ let coordinates;
233
380
  const blob = (file, commit) => {
234
381
  const key = `${commit}\0${file}`;
235
382
  if (!refs.has(key)) {
@@ -241,6 +388,7 @@ export const classifyEvidence = (cwd, commits, heads) => {
241
388
  return row => {
242
389
  if (
243
390
  row.RuleID !== "generic-api-key" ||
391
+ !selected.has(row.Commit) ||
244
392
  !safeSourcePath(row.File) ||
245
393
  row.SymlinkFile !== "" ||
246
394
  row.Secret !== "REDACTED" ||
@@ -256,15 +404,35 @@ export const classifyEvidence = (cwd, commits, heads) => {
256
404
  if (!bytes) return false;
257
405
  const span = attribution(row, bytes);
258
406
  if (!span) return false;
259
- const narrative = narrativeSpan(bytes, span.lineStart, span.lineEnd);
407
+ const narrative = paragraphNarrativeSpan(
408
+ bytes,
409
+ span.lineStart,
410
+ span.lineEnd
411
+ );
260
412
  if (narrative !== null && span.matches(narrative)) return true;
261
413
  const key = `${row.Commit}\0${row.File}`;
414
+ if (coordinates === undefined)
415
+ coordinates = selectedCoordinates(cwd, commits, blob);
262
416
  if (!maps.has(key))
263
417
  maps.set(
264
418
  key,
265
- evidenceMaps(bytes).flatMap(map =>
266
- verifiedMap(map, row, cwd, commits, heads, blob, versions)
267
- )
419
+ coordinates.present &&
420
+ (coordinates.entries === null ||
421
+ coordinates.documents.has(JSON.stringify([row.Commit, row.File])))
422
+ ? coordinateMaps(bytes).flatMap(map =>
423
+ verifiedCoordinateMap(
424
+ map,
425
+ row,
426
+ bytes,
427
+ coordinates.entries,
428
+ cwd,
429
+ selected,
430
+ blob
431
+ )
432
+ )
433
+ : evidenceMaps(bytes).flatMap(map =>
434
+ verifiedMap(map, row, cwd, commits, heads, blob, versions)
435
+ )
268
436
  );
269
437
  return maps.get(key).filter(span.matches).length === 1;
270
438
  };
@@ -34,6 +34,7 @@ import {
34
34
  import {
35
35
  DESCRIPTOR_KEYS,
36
36
  optionalLockFields,
37
+ optionalRuntimeFields,
37
38
  } from "./automation-provenance-contract.mjs";
38
39
 
39
40
  /** Only complete, digest-checked transport is considered; incomplete chunks grant nothing. */
@@ -181,7 +182,11 @@ export function originalDescriptor(checkpoint, old, allocation, authority) {
181
182
  const preview = checkpoint.payload.preview;
182
183
  keys(preview, ["descriptor", "message", "epoch"]);
183
184
  const d = preview.descriptor;
184
- keys(d, [...DESCRIPTOR_KEYS, ...optionalLockFields(old)]);
185
+ keys(d, [
186
+ ...DESCRIPTOR_KEYS,
187
+ ...optionalLockFields(old),
188
+ ...optionalRuntimeFields(old),
189
+ ]);
185
190
  required(
186
191
  d.version === 1 &&
187
192
  d.parent === old.parent &&
@@ -193,6 +198,7 @@ export function originalDescriptor(checkpoint, old, allocation, authority) {
193
198
  d.policySha256 === sha256(canonicalJson(authority)) &&
194
199
  canonicalJson(d.files) === canonicalJson(old.hashes) &&
195
200
  d.bunLockSha256 === old.bunLockSha256 &&
201
+ d.runtimeSha256 === old.runtimeSha256 &&
196
202
  canonicalJson(d.updates) === canonicalJson(old.updates) &&
197
203
  typeof preview.message === "string" &&
198
204
  sha256(preview.message) === d.messageSha256 &&
@@ -12,9 +12,12 @@ import { canonicalJson } from "../lisa-automation-provenance.mjs";
12
12
  import { sha256 } from "./github-attestation-verifier.mjs";
13
13
  import {
14
14
  optionalLockFields,
15
+ optionalRuntimeFields,
15
16
  proposalFileNames,
17
+ signedProposalFields,
16
18
  } from "./automation-provenance-contract.mjs";
17
19
  export { proposalFileNames } from "./automation-provenance-contract.mjs";
20
+ import { runtimeBinding } from "./npm-update-rails-runtime-contract.mjs";
18
21
 
19
22
  export const FILES = ["package-lock.json", "package.json"];
20
23
  export const SECTIONS = [
@@ -24,72 +27,10 @@ export const SECTIONS = [
24
27
  ];
25
28
  export const CLAIM =
26
29
  "[lisa-tracker-claim] Claimed by Lisa. Starting implementation.";
27
- export const NAME = /^(?:@[a-z0-9][a-z0-9_.-]*\/)?[a-z0-9][a-z0-9_.-]*$/;
28
- export const VERSION =
29
- /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[A-Za-z0-9.-]+)?$/;
30
+ export { NAME, VERSION, validatePolicy } from "./npm-update-policy.mjs";
31
+ import { VERSION } from "./npm-update-policy.mjs";
30
32
  export const OBJECT = /^[a-f0-9]{40}$/;
31
33
 
32
- /** Configured tracking and an explicit owner are prerequisites, never inferred. */
33
- export function validatePolicy(value, config) {
34
- keys(value, [
35
- "version",
36
- "repository",
37
- "directory",
38
- "target",
39
- "maintainer",
40
- "packages",
41
- "lisaOwner",
42
- ]);
43
- required(
44
- value.version === 1 && value.directory === "." && value.target === "main",
45
- "only root npm on main is supported"
46
- );
47
- required(
48
- config.tracker === "github" &&
49
- value.repository === `${config.github?.org}/${config.github?.repo}`,
50
- "configured repository/tracker differs"
51
- );
52
- required(
53
- /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(value.repository),
54
- "invalid repository"
55
- );
56
- required(
57
- typeof value.maintainer === "string" &&
58
- /^[A-Za-z0-9][A-Za-z0-9-]{0,38}$/.test(value.maintainer),
59
- "explicit assignable maintainer required"
60
- );
61
- required(
62
- ["absent", "verified-local-full-apply"].includes(value.lisaOwner),
63
- "Lisa requires a verified local full-apply owner"
64
- );
65
- required(
66
- Array.isArray(value.packages) &&
67
- value.packages.length > 0 &&
68
- value.packages.length <= 64,
69
- "invalid package selection"
70
- );
71
- const names = new Set();
72
- for (const selection of value.packages) {
73
- keys(selection, ["name", "version"]);
74
- required(
75
- typeof selection.name === "string" &&
76
- selection.name.length <= 214 &&
77
- NAME.test(selection.name),
78
- "invalid npm name"
79
- );
80
- required(
81
- typeof selection.version === "string" && VERSION.test(selection.version),
82
- "exact registry version required"
83
- );
84
- required(
85
- !names.has(selection.name) && selection.name !== "@codyswann/lisa",
86
- "duplicate selection or Lisa version-only update"
87
- );
88
- names.add(selection.name);
89
- }
90
- return structuredClone(value);
91
- }
92
-
93
34
  /** Host declarations are checked before npm or lifecycle execution. */
94
35
  export function validateHost(before) {
95
36
  required(
@@ -221,7 +162,10 @@ export function proposalFrom(
221
162
  bunLockSha256
222
163
  ) {
223
164
  required(OBJECT.test(parent), "unsupported Git parent or object format");
224
- const optional = bunLockSha256 === undefined ? {} : { bunLockSha256 };
165
+ const optional = {
166
+ ...(bunLockSha256 === undefined ? {} : { bunLockSha256 }),
167
+ ...runtimeBinding(policy),
168
+ };
225
169
  const names = proposalFileNames({ files, ...optional });
226
170
  for (const value of Object.values(files))
227
171
  required(
@@ -253,7 +197,7 @@ export function proposalFrom(
253
197
  repository: policy.repository,
254
198
  parent,
255
199
  updates: ordered,
256
- ...optional,
200
+ ...signedProposalFields(optional),
257
201
  })
258
202
  ),
259
203
  before,
@@ -280,6 +224,7 @@ export function validateProposal(value, policy) {
280
224
  "files",
281
225
  "hashes",
282
226
  ...optionalLockFields(value),
227
+ ...optionalRuntimeFields(value),
283
228
  ]);
284
229
  const expected = proposalFrom(
285
230
  policy,
@@ -128,6 +128,9 @@ export async function descriptorFor({
128
128
  ...(proposal.bunLockSha256 === undefined
129
129
  ? {}
130
130
  : { bunLockSha256: proposal.bunLockSha256 }),
131
+ ...(proposal.runtimeSha256 === undefined
132
+ ? {}
133
+ : { runtimeSha256: proposal.runtimeSha256 }),
131
134
  messageSha256: sha256(message),
132
135
  updates: proposal.updates,
133
136
  proposalKey: proposal.bindingKey,
@@ -65,6 +65,7 @@ const PRODUCER = [
65
65
  "helper-inventory",
66
66
  "hosted-gate",
67
67
  "hosted-hook",
68
+ "hosted-scope",
68
69
  "hook-installation",
69
70
  "hook-preload",
70
71
  "hook-provider",
@@ -78,12 +79,21 @@ const PRODUCER = [
78
79
  "object",
79
80
  "orchestrator",
80
81
  "owner",
82
+ "policy",
81
83
  "prepare",
82
84
  "process",
83
85
  "process-core",
84
86
  "publication",
85
87
  "publish",
86
88
  "quality",
89
+ "rails-mysql",
90
+ "rails-mysql-daemon",
91
+ "rails-mysql-resource",
92
+ "rails-mysql-storage",
93
+ "rails-runtime-contract",
94
+ "rails-tool-downloads",
95
+ "rails-tool-identity",
96
+ "rails-tools",
87
97
  "recovery",
88
98
  "supersession",
89
99
  "runtime-archive",