@clossys/launcher 0.3.0 → 0.4.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 (286) hide show
  1. package/README.md +1328 -60
  2. package/contracts/conversation-contract.md +2 -1
  3. package/contracts/product-ci-workflow.yml +74 -0
  4. package/contracts/repository-inventory.json +53 -0
  5. package/dist/admission-fixture.d.ts +168 -0
  6. package/dist/admission-fixture.d.ts.map +1 -0
  7. package/dist/admission-fixture.js +453 -0
  8. package/dist/admission-fixture.js.map +1 -0
  9. package/dist/admission.d.ts +124 -0
  10. package/dist/admission.d.ts.map +1 -0
  11. package/dist/admission.js +799 -0
  12. package/dist/admission.js.map +1 -0
  13. package/dist/agents-guide.d.ts +9 -0
  14. package/dist/agents-guide.d.ts.map +1 -0
  15. package/dist/agents-guide.js +26 -0
  16. package/dist/agents-guide.js.map +1 -0
  17. package/dist/apply-command-options.check.d.ts +12 -0
  18. package/dist/apply-command-options.check.d.ts.map +1 -0
  19. package/dist/apply-command-options.check.js +20 -0
  20. package/dist/apply-command-options.check.js.map +1 -0
  21. package/dist/apply-plan-cli.d.ts +39 -1
  22. package/dist/apply-plan-cli.d.ts.map +1 -1
  23. package/dist/apply-plan-cli.js +432 -15
  24. package/dist/apply-plan-cli.js.map +1 -1
  25. package/dist/apply-plan.d.ts +46 -59
  26. package/dist/apply-plan.d.ts.map +1 -1
  27. package/dist/apply-plan.js +112 -97
  28. package/dist/apply-plan.js.map +1 -1
  29. package/dist/apply-step-fixture.d.ts +87 -0
  30. package/dist/apply-step-fixture.d.ts.map +1 -0
  31. package/dist/apply-step-fixture.js +199 -0
  32. package/dist/apply-step-fixture.js.map +1 -0
  33. package/dist/apply-store.d.ts +93 -0
  34. package/dist/apply-store.d.ts.map +1 -0
  35. package/dist/apply-store.js +625 -0
  36. package/dist/apply-store.js.map +1 -0
  37. package/dist/approval-sheet.d.ts +21 -0
  38. package/dist/approval-sheet.d.ts.map +1 -0
  39. package/dist/approval-sheet.js +157 -0
  40. package/dist/approval-sheet.js.map +1 -0
  41. package/dist/body-command.d.ts +42 -0
  42. package/dist/body-command.d.ts.map +1 -0
  43. package/dist/body-command.js +143 -0
  44. package/dist/body-command.js.map +1 -0
  45. package/dist/change-set-contract.d.ts +381 -0
  46. package/dist/change-set-contract.d.ts.map +1 -0
  47. package/dist/change-set-contract.js +738 -0
  48. package/dist/change-set-contract.js.map +1 -0
  49. package/dist/change-set-digest.d.ts +28 -0
  50. package/dist/change-set-digest.d.ts.map +1 -0
  51. package/dist/change-set-digest.js +65 -0
  52. package/dist/change-set-digest.js.map +1 -0
  53. package/dist/check-cli.d.ts.map +1 -1
  54. package/dist/check-cli.js +14 -3
  55. package/dist/check-cli.js.map +1 -1
  56. package/dist/cli.d.ts +17 -6
  57. package/dist/cli.d.ts.map +1 -1
  58. package/dist/cli.js +84 -23
  59. package/dist/cli.js.map +1 -1
  60. package/dist/core.d.ts +79 -22
  61. package/dist/core.d.ts.map +1 -1
  62. package/dist/core.js +843 -268
  63. package/dist/core.js.map +1 -1
  64. package/dist/dry-materialize.d.ts +63 -0
  65. package/dist/dry-materialize.d.ts.map +1 -0
  66. package/dist/dry-materialize.js +330 -0
  67. package/dist/dry-materialize.js.map +1 -0
  68. package/dist/generated/contract-schema.generated.d.ts +97 -0
  69. package/dist/generated/contract-schema.generated.d.ts.map +1 -0
  70. package/dist/generated/contract-schema.generated.js +496 -0
  71. package/dist/generated/contract-schema.generated.js.map +1 -0
  72. package/dist/generated/package-scope.generated.d.ts +6 -0
  73. package/dist/generated/package-scope.generated.d.ts.map +1 -0
  74. package/dist/generated/package-scope.generated.js +10 -0
  75. package/dist/generated/package-scope.generated.js.map +1 -0
  76. package/dist/generated/plan-contracts.generated.d.ts +3 -0
  77. package/dist/generated/plan-contracts.generated.d.ts.map +1 -0
  78. package/dist/generated/plan-contracts.generated.js +2840 -0
  79. package/dist/generated/plan-contracts.generated.js.map +1 -0
  80. package/dist/host.d.ts.map +1 -1
  81. package/dist/host.js +11 -0
  82. package/dist/host.js.map +1 -1
  83. package/dist/identity.d.ts +15 -0
  84. package/dist/identity.d.ts.map +1 -0
  85. package/dist/identity.js +48 -0
  86. package/dist/identity.js.map +1 -0
  87. package/dist/index.d.ts +34 -5
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +19 -2
  90. package/dist/index.js.map +1 -1
  91. package/dist/inventory-adoption.d.ts +24 -5
  92. package/dist/inventory-adoption.d.ts.map +1 -1
  93. package/dist/inventory-adoption.js +70 -25
  94. package/dist/inventory-adoption.js.map +1 -1
  95. package/dist/inventory-choice.d.ts +40 -0
  96. package/dist/inventory-choice.d.ts.map +1 -0
  97. package/dist/inventory-choice.js +156 -0
  98. package/dist/inventory-choice.js.map +1 -0
  99. package/dist/inventory-contract.d.ts +89 -0
  100. package/dist/inventory-contract.d.ts.map +1 -0
  101. package/dist/inventory-contract.js +121 -0
  102. package/dist/inventory-contract.js.map +1 -0
  103. package/dist/key-editor.d.ts +30 -0
  104. package/dist/key-editor.d.ts.map +1 -0
  105. package/dist/key-editor.js +445 -0
  106. package/dist/key-editor.js.map +1 -0
  107. package/dist/ledger-contract.d.ts +187 -0
  108. package/dist/ledger-contract.d.ts.map +1 -0
  109. package/dist/ledger-contract.js +532 -0
  110. package/dist/ledger-contract.js.map +1 -0
  111. package/dist/ledger-trust.d.ts +90 -0
  112. package/dist/ledger-trust.d.ts.map +1 -0
  113. package/dist/ledger-trust.js +198 -0
  114. package/dist/ledger-trust.js.map +1 -0
  115. package/dist/lockfile-invariants.d.ts +48 -0
  116. package/dist/lockfile-invariants.d.ts.map +1 -0
  117. package/dist/lockfile-invariants.js +375 -0
  118. package/dist/lockfile-invariants.js.map +1 -0
  119. package/dist/lockfile-readers.d.ts +72 -0
  120. package/dist/lockfile-readers.d.ts.map +1 -0
  121. package/dist/lockfile-readers.js +713 -0
  122. package/dist/lockfile-readers.js.map +1 -0
  123. package/dist/lockfile-regen.d.ts +106 -0
  124. package/dist/lockfile-regen.d.ts.map +1 -0
  125. package/dist/lockfile-regen.js +760 -0
  126. package/dist/lockfile-regen.js.map +1 -0
  127. package/dist/lockfile-tool-env.d.ts +29 -0
  128. package/dist/lockfile-tool-env.d.ts.map +1 -0
  129. package/dist/lockfile-tool-env.js +111 -0
  130. package/dist/lockfile-tool-env.js.map +1 -0
  131. package/dist/materialize.d.ts +113 -0
  132. package/dist/materialize.d.ts.map +1 -0
  133. package/dist/materialize.js +840 -0
  134. package/dist/materialize.js.map +1 -0
  135. package/dist/observe-repository.d.ts +90 -0
  136. package/dist/observe-repository.d.ts.map +1 -0
  137. package/dist/observe-repository.js +1367 -0
  138. package/dist/observe-repository.js.map +1 -0
  139. package/dist/plan-bundle-setup-fixture.d.ts +68 -0
  140. package/dist/plan-bundle-setup-fixture.d.ts.map +1 -0
  141. package/dist/plan-bundle-setup-fixture.js +167 -0
  142. package/dist/plan-bundle-setup-fixture.js.map +1 -0
  143. package/dist/plan-bundle.d.ts +250 -0
  144. package/dist/plan-bundle.d.ts.map +1 -0
  145. package/dist/plan-bundle.js +827 -0
  146. package/dist/plan-bundle.js.map +1 -0
  147. package/dist/plan-command.d.ts +29 -0
  148. package/dist/plan-command.d.ts.map +1 -0
  149. package/dist/plan-command.js +493 -0
  150. package/dist/plan-command.js.map +1 -0
  151. package/dist/plan-contract.d.ts +153 -0
  152. package/dist/plan-contract.d.ts.map +1 -0
  153. package/dist/plan-contract.js +61 -0
  154. package/dist/plan-contract.js.map +1 -0
  155. package/dist/plan-digest.d.ts +25 -0
  156. package/dist/plan-digest.d.ts.map +1 -0
  157. package/dist/plan-digest.js +106 -0
  158. package/dist/plan-digest.js.map +1 -0
  159. package/dist/plan-rules.d.ts +23 -0
  160. package/dist/plan-rules.d.ts.map +1 -0
  161. package/dist/plan-rules.js +177 -0
  162. package/dist/plan-rules.js.map +1 -0
  163. package/dist/planned-bundle.d.ts +20 -0
  164. package/dist/planned-bundle.d.ts.map +1 -0
  165. package/dist/planned-bundle.js +191 -0
  166. package/dist/planned-bundle.js.map +1 -0
  167. package/dist/product-repository.d.ts +4 -0
  168. package/dist/product-repository.d.ts.map +1 -1
  169. package/dist/product-repository.js +9 -1
  170. package/dist/product-repository.js.map +1 -1
  171. package/dist/provenance-gate.d.ts +48 -0
  172. package/dist/provenance-gate.d.ts.map +1 -0
  173. package/dist/provenance-gate.js +324 -0
  174. package/dist/provenance-gate.js.map +1 -0
  175. package/dist/pull-request-body.d.ts +45 -0
  176. package/dist/pull-request-body.d.ts.map +1 -0
  177. package/dist/pull-request-body.js +232 -0
  178. package/dist/pull-request-body.js.map +1 -0
  179. package/dist/registry-snapshot.d.ts +141 -0
  180. package/dist/registry-snapshot.d.ts.map +1 -0
  181. package/dist/registry-snapshot.js +483 -0
  182. package/dist/registry-snapshot.js.map +1 -0
  183. package/dist/release-age-edit.d.ts +52 -0
  184. package/dist/release-age-edit.d.ts.map +1 -0
  185. package/dist/release-age-edit.js +413 -0
  186. package/dist/release-age-edit.js.map +1 -0
  187. package/dist/root-entries.d.ts +36 -0
  188. package/dist/root-entries.d.ts.map +1 -0
  189. package/dist/root-entries.js +80 -0
  190. package/dist/root-entries.js.map +1 -0
  191. package/dist/setup-template-scripts.d.ts +34 -0
  192. package/dist/setup-template-scripts.d.ts.map +1 -0
  193. package/dist/setup-template-scripts.js +557 -0
  194. package/dist/setup-template-scripts.js.map +1 -0
  195. package/dist/setup-templates.d.ts +54 -0
  196. package/dist/setup-templates.d.ts.map +1 -0
  197. package/dist/setup-templates.js +427 -0
  198. package/dist/setup-templates.js.map +1 -0
  199. package/dist/skills.d.ts +34 -1
  200. package/dist/skills.d.ts.map +1 -1
  201. package/dist/skills.js +129 -17
  202. package/dist/skills.js.map +1 -1
  203. package/dist/status.d.ts +63 -0
  204. package/dist/status.d.ts.map +1 -0
  205. package/dist/status.js +539 -0
  206. package/dist/status.js.map +1 -0
  207. package/dist/types.d.ts +151 -13
  208. package/dist/types.d.ts.map +1 -1
  209. package/package.json +4 -5
  210. package/skeleton/README.md +14 -9
  211. package/skeleton/package.json +2 -1
  212. package/skill/SKILL.md +20 -16
  213. package/skill-catalogue/advisor/SKILL.md +100 -11
  214. package/skill-catalogue/architect/SKILL.md +2 -13
  215. package/skill-catalogue/bouncer/SKILL.md +2 -13
  216. package/skill-catalogue/builder/SKILL.md +2 -13
  217. package/skill-catalogue/butler/SKILL.md +2 -13
  218. package/skill-catalogue/controller/SKILL.md +2 -13
  219. package/skill-catalogue/customer/SKILL.md +4 -13
  220. package/skill-catalogue/designer/SKILL.md +9 -14
  221. package/skill-catalogue/giver/SKILL.md +2 -13
  222. package/skill-catalogue/influencer/SKILL.md +2 -13
  223. package/skill-catalogue/inspector/SKILL.md +2 -13
  224. package/skill-catalogue/integrator/SKILL.md +2 -13
  225. package/skill-catalogue/keeper/SKILL.md +2 -13
  226. package/skill-catalogue/launcher/SKILL.md +20 -16
  227. package/skill-catalogue/locksmith/SKILL.md +2 -13
  228. package/skill-catalogue/messenger/SKILL.md +2 -13
  229. package/skill-catalogue/observer/SKILL.md +2 -13
  230. package/skill-catalogue/publisher/SKILL.md +11 -17
  231. package/skill-catalogue/starter/SKILL.md +3 -13
  232. package/skill-catalogue/strategist/SKILL.md +14 -17
  233. package/skill-catalogue/writer/SKILL.md +7 -14
  234. package/src/admission-fixture.ts +572 -0
  235. package/src/admission.ts +816 -0
  236. package/src/agents-guide.ts +29 -0
  237. package/src/apply-command-options.check.ts +27 -0
  238. package/src/apply-plan-cli.ts +454 -14
  239. package/src/apply-plan.ts +112 -124
  240. package/src/apply-step-fixture.ts +236 -0
  241. package/src/apply-store.ts +584 -0
  242. package/src/approval-sheet.ts +164 -0
  243. package/src/body-command.ts +162 -0
  244. package/src/change-set-contract.ts +937 -0
  245. package/src/change-set-digest.ts +70 -0
  246. package/src/check-cli.ts +14 -3
  247. package/src/cli.ts +90 -22
  248. package/src/core.ts +973 -275
  249. package/src/dry-materialize.ts +353 -0
  250. package/src/generated/contract-schema.generated.ts +520 -0
  251. package/src/generated/package-scope.generated.ts +10 -0
  252. package/src/generated/plan-contracts.generated.ts +2840 -0
  253. package/src/host.ts +10 -0
  254. package/src/identity.ts +51 -0
  255. package/src/index.ts +72 -3
  256. package/src/inventory-adoption.ts +107 -29
  257. package/src/inventory-choice.ts +172 -0
  258. package/src/inventory-contract.ts +166 -0
  259. package/src/key-editor.ts +446 -0
  260. package/src/ledger-contract.ts +637 -0
  261. package/src/ledger-trust.ts +267 -0
  262. package/src/lockfile-invariants.ts +421 -0
  263. package/src/lockfile-readers.ts +749 -0
  264. package/src/lockfile-regen.ts +851 -0
  265. package/src/lockfile-tool-env.ts +131 -0
  266. package/src/materialize.ts +886 -0
  267. package/src/observe-repository.ts +1365 -0
  268. package/src/plan-bundle-setup-fixture.ts +200 -0
  269. package/src/plan-bundle.ts +964 -0
  270. package/src/plan-command.ts +509 -0
  271. package/src/plan-contract.ts +179 -0
  272. package/src/plan-digest.ts +102 -0
  273. package/src/plan-rules.ts +188 -0
  274. package/src/planned-bundle.ts +211 -0
  275. package/src/product-repository.ts +10 -1
  276. package/src/provenance-gate.ts +352 -0
  277. package/src/pull-request-body.ts +261 -0
  278. package/src/registry-snapshot.ts +534 -0
  279. package/src/release-age-edit.ts +430 -0
  280. package/src/root-entries.ts +81 -0
  281. package/src/setup-template-scripts.ts +571 -0
  282. package/src/setup-templates.ts +471 -0
  283. package/src/skills.ts +161 -18
  284. package/src/status.ts +557 -0
  285. package/src/types.ts +148 -13
  286. package/CHANGELOG.md +0 -131
@@ -0,0 +1,90 @@
1
+ import type { ChangeSetPhase, RepositoryChangeSet } from "./change-set-contract.js";
2
+ import type { InstalledLedger, LedgerPackageIdentity } from "./ledger-contract.js";
3
+ /** Plan package identities for one plan digest; deferred rows are trusted only against these acts. */
4
+ export interface PlanPackageActs {
5
+ readonly planDigest: string;
6
+ readonly packages: readonly (LedgerPackageIdentity & {
7
+ readonly act: "install" | "pin-starter";
8
+ })[];
9
+ }
10
+ export interface TrustInstalledLedgerOptions {
11
+ readonly planPackageActs?: readonly PlanPackageActs[];
12
+ }
13
+ /**
14
+ * Why a ledger is not trusted. ledger-unreadable: the bytes are not a valid,
15
+ * exactly canonical ledger. identity: its repository.nodeId is not the
16
+ * observed repository's (T11). renamed: its repository.id is not exactly the
17
+ * observed id -- a difference in letter case alone is still a rename, because
18
+ * a ledger generation can never change the id's case (SUCCESSION S2 and code
19
+ * rule L10 both require an exact match). ledger-chain: some history entry is
20
+ * not a held, self-verifying, valid change set that agrees with it. and
21
+ * ledger-foreign-row: some row is not a write of the change set it names (T9).
22
+ */
23
+ export type LedgerTrustRule = "ledger-unreadable" | "identity" | "renamed" | "ledger-chain" | "ledger-foreign-row";
24
+ /** The trust verdict on one repository's ledger: trusted (null when the repository has none, generation 0), or refused by one rule. */
25
+ export type LedgerTrust = {
26
+ readonly state: "trusted";
27
+ readonly ledger: InstalledLedger | null;
28
+ } | {
29
+ readonly state: "refused";
30
+ readonly rule: LedgerTrustRule;
31
+ };
32
+ /**
33
+ * Whether the planner may build on a repository's ledger. `bytes` is the exact
34
+ * text of clossys/.state/installed.json at the base (null when there is none),
35
+ * `observed` the repository's observed id and immutable node id, and `held`
36
+ * the change sets the hub holds (any repository's; each is re-verified here).
37
+ * Checks, in order: no ledger is trusted at generation 0; unreadable bytes;
38
+ * node id (identity); id, compared exactly -- a difference in letter case
39
+ * alone is still refused as renamed (ledger-trust.ts); every history entry
40
+ * matched by a held, valid, self-verifying set that agrees with it on phase,
41
+ * planDigest, bundle, baseCommit, node id and the generation it was computed
42
+ * over (ledger-chain); and every row a write of its matched set
43
+ * (ledger-foreign-row). A refusal carries the rule only.
44
+ */
45
+ export declare function trustInstalledLedger(bytes: Uint8Array | null, observed: {
46
+ readonly id: string;
47
+ readonly nodeId: string;
48
+ }, held: readonly RepositoryChangeSet[], options?: TrustInstalledLedgerOptions): LedgerTrust;
49
+ /** What the planner knows about one whole file it wants to write. */
50
+ export interface WholeFileState {
51
+ readonly path: string;
52
+ /** The content digest the set wants at the path. */
53
+ readonly desired: string;
54
+ /** The trusted ledger's files row `after` at the path (compared case-insensitively), or null when it has none. */
55
+ readonly row: string | null;
56
+ /** The base's content digest at the path; null when no file is there. */
57
+ readonly base: string | null;
58
+ /** Whether the base has anything at the path: a file, or a directory holding one. */
59
+ readonly occupied: boolean;
60
+ readonly phase: ChangeSetPhase;
61
+ /** The base's composed-skill manifest (clossys/.state/skills.json), read by the caller, or null when absent or unreadable; `sha256` is 64 hex digits with no prefix. */
62
+ readonly skillsManifest: readonly {
63
+ readonly name: string;
64
+ readonly sha256: string;
65
+ }[] | null;
66
+ }
67
+ /** Whether to write a whole file and from which `before` (null: add; equal to the desired digest: keep; else update), or why not. */
68
+ export type WholeFileOutcome = {
69
+ readonly write: true;
70
+ readonly before: string | null;
71
+ } | {
72
+ readonly write: false;
73
+ readonly reason: "unowned-existing" | "client-edited" | "deleted";
74
+ };
75
+ /**
76
+ * The compare-and-swap table for one whole file (RFC §12.1), total over its
77
+ * inputs and the one place it lives:
78
+ *
79
+ * ledger row base result
80
+ * none nothing there write, before null (add)
81
+ * none occupied, adoptable write, before = base (adopted)
82
+ * none occupied, not adoptable unowned-existing
83
+ * h h write, before h (keep or update)
84
+ * h nothing there deleted (never folded into an update; D13)
85
+ * h occupied by other bytes client-edited (D11)
86
+ *
87
+ * Adoption happens only in a setup set; an apply set never adopts.
88
+ */
89
+ export declare function reconcileWholeFile(state: WholeFileState): WholeFileOutcome;
90
+ //# sourceMappingURL=ledger-trust.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger-trust.d.ts","sourceRoot":"","sources":["../src/ledger-trust.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAiB,cAAc,EAAc,mBAAmB,EAAmB,MAAM,0BAA0B,CAAC;AAGhI,OAAO,KAAK,EAAE,eAAe,EAAyD,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAE1I,sGAAsG;AACtG,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,qBAAqB,GAAG;QAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,GAAG,aAAa,CAAA;KAAE,CAAC,EAAE,CAAC;CACrG;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;CACvD;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,eAAe,GAAG,mBAAmB,GAAG,UAAU,GAAG,SAAS,GAAG,cAAc,GAAG,oBAAoB,CAAC;AAEnH,uIAAuI;AACvI,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAAA;CAAE,GACtE;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AA8GlE;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,UAAU,GAAG,IAAI,EACxB,QAAQ,EAAE;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC1D,IAAI,EAAE,SAAS,mBAAmB,EAAE,EACpC,OAAO,CAAC,EAAE,2BAA2B,GACpC,WAAW,CAyBb;AAED,qEAAqE;AACrE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kHAAkH;IAClH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,wKAAwK;IACxK,QAAQ,CAAC,cAAc,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,IAAI,CAAC;CAC/F;AAED,qIAAqI;AACrI,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,GAAG,eAAe,GAAG,SAAS,CAAA;CAAE,CAAC;AAuBjG;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,gBAAgB,CAS1E"}
@@ -0,0 +1,198 @@
1
+ // Whether the apply planner may trust a repository's installed-state ledger
2
+ // (issue #1178; docs/rfcs/apply-approved-plan.md §12.1, §12.2 and §12.8), and
3
+ // the one compare-and-swap table for a whole file. A ledger is a claim anyone
4
+ // with write access could have edited (TRUST in installed-ledger.json, in the
5
+ // public repository, not shipped in this package): it is trusted only when
6
+ // every generation it records is a change set the hub holds as a
7
+ // self-verifying set, and every row it carries is one of those sets' own
8
+ // writes. Anything less refuses the whole repository, never one row: RENDER
9
+ // re-publishes every row it keeps, so a row the hub cannot account for would
10
+ // otherwise be laundered into the next generation.
11
+ //
12
+ // Pure: no I/O, no clock, no randomness. The caller reads the ledger's bytes
13
+ // and the held change sets; this module only compares them. A refusal carries
14
+ // a rule id and nothing else, never a path, id, digest or other value.
15
+ import { EXEMPTION_SURFACES, validateRepositoryChangeSet } from "./change-set-contract.js";
16
+ import { changeSetDigest } from "./change-set-digest.js";
17
+ import { readInstalledLedger } from "./ledger-contract.js";
18
+ const isWhole = (file) => !("derived" in file);
19
+ const isPackageItem = (item) => item.act === "install" || item.act === "pin-starter";
20
+ /** Whether a path refusal of `set` names the item: RENDER adds no entries row for such an item. */
21
+ function pathRefused(set, itemId) {
22
+ return set.refused.some((refusal) => "path" in refusal && refusal.item === itemId);
23
+ }
24
+ /** Whether a key refusal of `set` names the item: RENDER adds no packages row for such an item. */
25
+ function keyRefused(set, itemId) {
26
+ return set.refused.some((refusal) => "pointer" in refusal && refusal.item === itemId);
27
+ }
28
+ /** Whether a held set is valid under its contract and its digest recomputes to the one it carries. Never throws. */
29
+ function selfVerifying(set) {
30
+ try {
31
+ return validateRepositoryChangeSet(set).valid && changeSetDigest(set) === set.changeSetDigest;
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ /** The held set that wrote history[index], agreeing with the entry on everything a set carries, or undefined. */
38
+ function matchHistoryEntry(entry, index, nodeId, held, verified) {
39
+ // Several held sets may share a digest and differ in `bundle`, which is outside the digest and not compared here.
40
+ return held.find((set) => set?.changeSetDigest === entry.changeSet &&
41
+ set.phase === entry.phase &&
42
+ set.planDigest === entry.planDigest &&
43
+ set.repository?.baseCommit === entry.baseCommit &&
44
+ set.repository?.nodeId === nodeId &&
45
+ set.ledger?.generation === index &&
46
+ verified(set));
47
+ }
48
+ function entryRowWritten(set, row) {
49
+ return set.items.some((item) => {
50
+ if (item.act === "exempt-release-age") {
51
+ return item.path === row.file && EXEMPTION_SURFACES[item.surface].key === row.key && `${item.scope}/*` === row.value && !pathRefused(set, item.id);
52
+ }
53
+ if (item.act === "declare-root-entry") {
54
+ return item.path === row.file && row.key === "rootEntries" && item.entries.some((entry) => entry.name === row.value) && !pathRefused(set, item.id);
55
+ }
56
+ return false;
57
+ });
58
+ }
59
+ function deferredRowWritten(ledger, row, set, planPackageActs) {
60
+ if (!set.deferred.some((deferral) => deferral.planItem === row.planItem))
61
+ return false;
62
+ const entry = ledger.history.find((history) => history.changeSet === row.changeSet);
63
+ if (entry === undefined)
64
+ return false;
65
+ const bundle = planPackageActs?.find((acts) => acts.planDigest === entry.planDigest);
66
+ if (bundle === undefined)
67
+ return false;
68
+ const act = bundle.packages.find((candidate) => candidate.planItem === row.planItem);
69
+ if (act === undefined)
70
+ return false;
71
+ return row.act === act.act && row.name === act.name && row.version === act.version && row.integrity === act.integrity && row.placement === act.placement;
72
+ }
73
+ /** Whether every row of the ledger is a write of the change set it names (L4 makes each name a history entry's). */
74
+ function rowsWritten(ledger, bySet, planPackageActs) {
75
+ const setOf = (changeSet) => bySet.get(changeSet);
76
+ return (ledger.files.every((row) => {
77
+ const set = setOf(row.changeSet);
78
+ return set !== undefined && set.files.some((file) => isWhole(file) && file.path === row.path && file.mode === row.mode && file.after === row.after);
79
+ }) &&
80
+ ledger.keys.every((row) => {
81
+ const set = setOf(row.changeSet);
82
+ return set !== undefined && set.keys.some((key) => key.file === row.file && key.pointer === row.pointer && key.after === row.value);
83
+ }) &&
84
+ ledger.packages.every((row) => {
85
+ const set = setOf(row.changeSet);
86
+ return (set !== undefined &&
87
+ set.items.some((item) => isPackageItem(item) &&
88
+ item.planItem === row.planItem &&
89
+ item.act === row.act &&
90
+ item.package.name === row.name &&
91
+ item.package.version === row.version &&
92
+ item.package.integrity === row.integrity &&
93
+ item.placement === row.placement &&
94
+ !keyRefused(set, item.id)));
95
+ }) &&
96
+ ledger.entries.every((row) => {
97
+ const set = setOf(row.changeSet);
98
+ return set !== undefined && entryRowWritten(set, row);
99
+ }) &&
100
+ ledger.deferred.every((row) => {
101
+ const set = setOf(row.changeSet);
102
+ return set !== undefined && deferredRowWritten(ledger, row, set, planPackageActs);
103
+ }));
104
+ }
105
+ /**
106
+ * Whether the planner may build on a repository's ledger. `bytes` is the exact
107
+ * text of clossys/.state/installed.json at the base (null when there is none),
108
+ * `observed` the repository's observed id and immutable node id, and `held`
109
+ * the change sets the hub holds (any repository's; each is re-verified here).
110
+ * Checks, in order: no ledger is trusted at generation 0; unreadable bytes;
111
+ * node id (identity); id, compared exactly -- a difference in letter case
112
+ * alone is still refused as renamed (ledger-trust.ts); every history entry
113
+ * matched by a held, valid, self-verifying set that agrees with it on phase,
114
+ * planDigest, bundle, baseCommit, node id and the generation it was computed
115
+ * over (ledger-chain); and every row a write of its matched set
116
+ * (ledger-foreign-row). A refusal carries the rule only.
117
+ */
118
+ export function trustInstalledLedger(bytes, observed, held, options) {
119
+ const refuse = (rule) => ({ state: "refused", rule });
120
+ if (bytes === null)
121
+ return { state: "trusted", ledger: null };
122
+ const ledger = readInstalledLedger(bytes);
123
+ if (ledger === null)
124
+ return refuse("ledger-unreadable");
125
+ if (ledger.repository.nodeId !== observed.nodeId)
126
+ return refuse("identity");
127
+ if (ledger.repository.id !== observed.id)
128
+ return refuse("renamed");
129
+ const checked = new Map();
130
+ const verified = (set) => {
131
+ let result = checked.get(set);
132
+ if (result === undefined) {
133
+ result = selfVerifying(set);
134
+ checked.set(set, result);
135
+ }
136
+ return result;
137
+ };
138
+ const bySet = new Map();
139
+ for (const [index, entry] of ledger.history.entries()) {
140
+ const set = matchHistoryEntry(entry, index, ledger.repository.nodeId, held, verified);
141
+ if (set === undefined)
142
+ return refuse("ledger-chain");
143
+ bySet.set(entry.changeSet, set);
144
+ }
145
+ if (!rowsWritten(ledger, bySet, options?.planPackageActs))
146
+ return refuse("ledger-foreign-row");
147
+ return { state: "trusted", ledger };
148
+ }
149
+ const SKILL_FILE = /^\.agents\/skills\/clossys-([^/]+)\/skill\.md$/iu;
150
+ /**
151
+ * The generation-0 adoption pass (RFC §12.2): only in a setup set, only over
152
+ * a file that is there, and only when its bytes provably are flow output --
153
+ * the bytes the set would write, or a composed skill whose digest the base's
154
+ * skills manifest records. clossys/.state/skills.json itself is client
155
+ * controlled and proves nothing about its own bytes, so it is adopted only
156
+ * through the first branch, when its base already holds the bytes the set
157
+ * would write; nothing else about it is ever adopted.
158
+ */
159
+ function adoptable(state) {
160
+ const { base } = state;
161
+ if (state.phase !== "setup" || base === null)
162
+ return false;
163
+ if (base === state.desired)
164
+ return true;
165
+ const manifest = state.skillsManifest;
166
+ if (manifest === null)
167
+ return false;
168
+ const role = SKILL_FILE.exec(state.path)?.[1]?.toLowerCase();
169
+ return role !== undefined && manifest.some((entry) => entry.name === role && `sha256:${entry.sha256}` === base);
170
+ }
171
+ /**
172
+ * The compare-and-swap table for one whole file (RFC §12.1), total over its
173
+ * inputs and the one place it lives:
174
+ *
175
+ * ledger row base result
176
+ * none nothing there write, before null (add)
177
+ * none occupied, adoptable write, before = base (adopted)
178
+ * none occupied, not adoptable unowned-existing
179
+ * h h write, before h (keep or update)
180
+ * h nothing there deleted (never folded into an update; D13)
181
+ * h occupied by other bytes client-edited (D11)
182
+ *
183
+ * Adoption happens only in a setup set; an apply set never adopts.
184
+ */
185
+ export function reconcileWholeFile(state) {
186
+ const occupied = state.occupied || state.base !== null;
187
+ if (state.row === null) {
188
+ if (!occupied)
189
+ return { write: true, before: null };
190
+ return adoptable(state) ? { write: true, before: state.base } : { write: false, reason: "unowned-existing" };
191
+ }
192
+ if (state.base === state.row)
193
+ return { write: true, before: state.row };
194
+ if (!occupied)
195
+ return { write: false, reason: "deleted" };
196
+ return { write: false, reason: "client-edited" };
197
+ }
198
+ //# sourceMappingURL=ledger-trust.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger-trust.js","sourceRoot":"","sources":["../src/ledger-trust.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,8EAA8E;AAC9E,8EAA8E;AAC9E,8EAA8E;AAC9E,2EAA2E;AAC3E,iEAAiE;AACjE,yEAAyE;AACzE,4EAA4E;AAC5E,6EAA6E;AAC7E,mDAAmD;AACnD,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,uEAAuE;AAEvE,OAAO,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAE3F,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAgC3D,MAAM,OAAO,GAAG,CAAC,IAAgB,EAA2B,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;AACpF,MAAM,aAAa,GAAG,CAAC,IAAmB,EAAuB,EAAE,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,KAAK,aAAa,CAAC;AAEzH,mGAAmG;AACnG,SAAS,WAAW,CAAC,GAAwB,EAAE,MAAc;IAC3D,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;AACrF,CAAC;AAED,mGAAmG;AACnG,SAAS,UAAU,CAAC,GAAwB,EAAE,MAAc;IAC1D,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;AACxF,CAAC;AAED,oHAAoH;AACpH,SAAS,aAAa,CAAC,GAAwB;IAC7C,IAAI,CAAC;QACH,OAAO,2BAA2B,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,eAAe,CAAC;IAChG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,iHAAiH;AACjH,SAAS,iBAAiB,CACxB,KAAyB,EACzB,KAAa,EACb,MAAc,EACd,IAAoC,EACpC,QAA+C;IAE/C,kHAAkH;IAClH,OAAO,IAAI,CAAC,IAAI,CACd,CAAC,GAAG,EAAE,EAAE,CACN,GAAG,EAAE,eAAe,KAAK,KAAK,CAAC,SAAS;QACxC,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;QACzB,GAAG,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU;QACnC,GAAG,CAAC,UAAU,EAAE,UAAU,KAAK,KAAK,CAAC,UAAU;QAC/C,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM;QACjC,GAAG,CAAC,MAAM,EAAE,UAAU,KAAK,KAAK;QAChC,QAAQ,CAAC,GAAG,CAAC,CAChB,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,GAAwB,EAAE,GAAmB;IACpE,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QAC7B,IAAI,IAAI,CAAC,GAAG,KAAK,oBAAoB,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,GAAG,CAAC,KAAK,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACrJ,CAAC;QACD,IAAI,IAAI,CAAC,GAAG,KAAK,oBAAoB,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,GAAG,KAAK,aAAa,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACrJ,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,kBAAkB,CAAC,MAAuB,EAAE,GAAsB,EAAE,GAAwB,EAAE,eAAuD;IAC5J,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACvF,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS,CAAC,CAAC;IACpF,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,MAAM,GAAG,eAAe,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU,CAAC,CAAC;IACrF,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACvC,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC;IACrF,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACpC,OAAO,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS,CAAC;AAC3J,CAAC;AAED,oHAAoH;AACpH,SAAS,WAAW,CAAC,MAAuB,EAAE,KAA+C,EAAE,eAAuD;IACpJ,MAAM,KAAK,GAAG,CAAC,SAAiB,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC1D,OAAO,CACL,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACzB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjC,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC;IACtJ,CAAC,CAAC;QACF,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACxB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACjC,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC;QACtI,CAAC,CAAC;QACF,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YAC5B,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACjC,OAAO,CACL,GAAG,KAAK,SAAS;gBACjB,GAAG,CAAC,KAAK,CAAC,IAAI,CACZ,CAAC,IAAI,EAAE,EAAE,CACP,aAAa,CAAC,IAAI,CAAC;oBACnB,IAAI,CAAC,QAAQ,KAAK,GAAG,CAAC,QAAQ;oBAC9B,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG;oBACpB,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI;oBAC9B,IAAI,CAAC,OAAO,CAAC,OAAO,KAAK,GAAG,CAAC,OAAO;oBACpC,IAAI,CAAC,OAAO,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS;oBACxC,IAAI,CAAC,SAAS,KAAK,GAAG,CAAC,SAAS;oBAChC,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAC5B,CACF,CAAC;QACJ,CAAC,CAAC;QACF,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YAC3B,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACjC,OAAO,GAAG,KAAK,SAAS,IAAI,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxD,CAAC,CAAC;QACF,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YAC5B,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACjC,OAAO,GAAG,KAAK,SAAS,IAAI,kBAAkB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,CAAC,CAAC;QACpF,CAAC,CAAC,CACH,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,oBAAoB,CAClC,KAAwB,EACxB,QAA0D,EAC1D,IAAoC,EACpC,OAAqC;IAErC,MAAM,MAAM,GAAG,CAAC,IAAqB,EAAe,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpF,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC9D,MAAM,MAAM,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAC1C,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACxD,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5E,IAAI,MAAM,CAAC,UAAU,CAAC,EAAE,KAAK,QAAQ,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC;IAEnE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAgC,CAAC;IACxD,MAAM,QAAQ,GAAG,CAAC,GAAwB,EAAE,EAAE;QAC5C,IAAI,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC9B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,IAAI,GAAG,EAA+B,CAAC;IACrD,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QACtD,MAAM,GAAG,GAAG,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;QACtF,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC,cAAc,CAAC,CAAC;QACrD,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,eAAe,CAAC;QAAE,OAAO,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAC/F,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AACtC,CAAC;AAuBD,MAAM,UAAU,GAAG,kDAAkD,CAAC;AAEtE;;;;;;;;GAQG;AACH,SAAS,SAAS,CAAC,KAAqB;IACtC,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC;IACvB,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC3D,IAAI,IAAI,KAAK,KAAK,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,cAAc,CAAC;IACtC,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7D,OAAO,IAAI,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,IAAI,UAAU,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC;AAClH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAqB;IACtD,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;IACvD,IAAI,KAAK,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,QAAQ;YAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QACpD,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC/G,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,GAAG;QAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;IACxE,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC1D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;AACnD,CAAC"}
@@ -0,0 +1,48 @@
1
+ import type { DependencyPlacement } from "./change-set-contract.js";
2
+ import type { LockfileFormat, LockfileUnreadableReason } from "./lockfile-readers.js";
3
+ export type LockfileInvariantId = "I1" | "I2" | "I3" | "I4" | "I5";
4
+ /** One approved package the regenerated lockfile must resolve exactly. */
5
+ export interface LockfileInvariantPackage {
6
+ readonly name: string;
7
+ readonly version: string;
8
+ readonly integrity: string;
9
+ readonly placement: DependencyPlacement;
10
+ }
11
+ export interface LockfileInvariantInput {
12
+ readonly format: LockfileFormat;
13
+ readonly base: string;
14
+ readonly regenerated: string;
15
+ readonly packages: readonly LockfileInvariantPackage[];
16
+ /** Defaults to PACKAGE_SCOPE. */
17
+ readonly publishing?: {
18
+ readonly scope: string;
19
+ readonly registry: string;
20
+ };
21
+ }
22
+ export interface LockfileInvariantViolation {
23
+ readonly invariant: LockfileInvariantId;
24
+ /** The package name this violation is about; "" for I4, whose violation is about the lockfile format as a whole, not one package. */
25
+ readonly name: string;
26
+ }
27
+ export interface TransitiveCounts {
28
+ /** `name@version` present after and not before. */
29
+ readonly added: number;
30
+ /** `name@version` present before and not after. */
31
+ readonly removed: number;
32
+ }
33
+ export type LockfileInvariantResult = {
34
+ readonly verdict: "satisfied";
35
+ readonly violations: readonly [];
36
+ readonly transitive: TransitiveCounts;
37
+ } | {
38
+ readonly verdict: "violated";
39
+ readonly violations: readonly LockfileInvariantViolation[];
40
+ readonly transitive: TransitiveCounts;
41
+ } | {
42
+ readonly verdict: "indeterminate";
43
+ readonly reason: LockfileUnreadableReason;
44
+ readonly side: "base" | "regenerated";
45
+ };
46
+ /** Checks I1 to I5 between a base and a regenerated lockfile. Pure; never throws. */
47
+ export declare function checkLockfileInvariants(input: LockfileInvariantInput): LockfileInvariantResult;
48
+ //# sourceMappingURL=lockfile-invariants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lockfile-invariants.d.ts","sourceRoot":"","sources":["../src/lockfile-invariants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGpE,OAAO,KAAK,EAAiB,cAAc,EAAE,wBAAwB,EAAgC,MAAM,uBAAuB,CAAC;AAGnI,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEnE,0EAA0E;AAC1E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC;CACzC;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,SAAS,wBAAwB,EAAE,CAAC;IACvD,iCAAiC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7E;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAC;IACxC,qIAAqI;IACrI,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,uBAAuB,GAC/B;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,EAAE,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAA;CAAE,GAC1G;IAAE,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAA;CAAE,GACnI;IAAE,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAAA;CAAE,CAAC;AAoX5H,qFAAqF;AACrF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,sBAAsB,GAAG,uBAAuB,CAM9F"}