@geonosis/release 1.4.0 → 2.1.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.
@@ -1,99 +1,46 @@
1
1
  import {
2
+ ADOPTION_NEXT,
2
3
  CannotRun,
4
+ DEFAULT_REGISTRY,
5
+ MIGRATIONS_NEXT,
6
+ PUBLISHED_NEXT,
7
+ SCHEMA_NEXT,
8
+ SMOKE_NEXT,
9
+ adoptionEnvelope,
10
+ comparisonsIn,
11
+ formatAdoption,
12
+ formatBaseline,
3
13
  formatDeployed,
4
14
  formatMigrations,
5
15
  formatPlan,
6
16
  formatProve,
17
+ formatPublished,
18
+ formatSchema,
19
+ formatSnapshot,
20
+ formatSweep,
7
21
  formatVerdict,
22
+ migrationsEnvelope,
8
23
  prove,
9
24
  proveOver,
25
+ publishedEnvelope,
26
+ readReleaseConfig,
27
+ recordBaseline,
28
+ runAdoption,
10
29
  runDeployed,
11
30
  runMigrations,
12
- runPlan
13
- } from "./chunk-D5IC766I.js";
14
-
15
- // src/release-cli.ts
16
- import { resolve } from "path";
17
-
18
- // src/envelope.ts
19
- import { mkdirSync, readFileSync, writeFileSync } from "fs";
20
- import { dirname, join } from "path";
21
- import { fileURLToPath } from "url";
22
- var ENVELOPES_DIR = ".geonosis/envelopes";
23
- var envelopePath = (root, tool) => join(root, ENVELOPES_DIR, `${tool}.json`);
24
- var UnbalancedEnvelope = class extends Error {
25
- constructor(message) {
26
- super(message);
27
- this.name = "UnbalancedEnvelope";
28
- }
29
- };
30
- var isCount = (value) => Number.isSafeInteger(value) && value >= 0;
31
- var unbalancedMessage = (envelope, next) => `${envelope.tool}: considered ${envelope.considered} but accounts for ${envelope.read + envelope.refused.length + envelope.excused.length} \u2014 ${envelope.read} read + ${envelope.refused.length} refused + ${envelope.excused.length} excused. A run that has lost count of its own inputs cannot say what it measured, so no verdict was rendered and no envelope was written. Next: ${next}`;
32
- var writeEnvelope = ({
33
- envelope,
34
- next,
35
- root
36
- }) => {
37
- if (envelope.tool.trim() === "") {
38
- throw new UnbalancedEnvelope(
39
- `an envelope with no tool name cannot be filed or reported against. Next: ${next}`
40
- );
41
- }
42
- if (envelope.version.trim() === "") {
43
- throw new UnbalancedEnvelope(
44
- `${envelope.tool}: an envelope that cannot name the build that wrote it dates nothing, and a stale one reads exactly like a fresh one. Next: ${next}`
45
- );
46
- }
47
- if (!isCount(envelope.considered) || !isCount(envelope.read)) {
48
- throw new UnbalancedEnvelope(
49
- `${envelope.tool}: considered ${envelope.considered} and read ${envelope.read} \u2014 a census is a whole number of things, and arithmetic over anything else balances by accident. Next: ${next}`
50
- );
51
- }
52
- if (envelope.considered !== envelope.read + envelope.refused.length + envelope.excused.length) {
53
- throw new UnbalancedEnvelope(unbalancedMessage(envelope, next));
54
- }
55
- const at = envelopePath(root, envelope.tool);
56
- mkdirSync(dirname(at), { recursive: true });
57
- writeFileSync(at, `${JSON.stringify(envelope, void 0, 2)}
58
- `);
59
- return at;
60
- };
61
- var UNKNOWN = "unknown";
62
- var versionIn = (dir) => {
63
- try {
64
- const manifest = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
65
- return typeof manifest.version === "string" ? manifest.version : void 0;
66
- } catch {
67
- return void 0;
68
- }
69
- };
70
- var versionOf = (moduleUrl) => {
71
- let dir = dirname(fileURLToPath(moduleUrl));
72
- for (; ; ) {
73
- const found = versionIn(dir);
74
- if (found !== void 0) return found;
75
- const up = dirname(dir);
76
- if (up === dir) return UNKNOWN;
77
- dir = up;
78
- }
79
- };
80
- var MIGRATIONS_TOOL = "release-migrations";
81
- var MIGRATIONS_NEXT = "geonosis-release migrations --since <ref> --json and compare `files` against `unreadable` \u2014 every added file leaves by exactly one door, and a file in one list and not the other is the accounting bug this refuses over";
82
- var migrationsEnvelope = (report, durationMs) => ({
83
- considered: report.files.length,
84
- durationMs,
85
- excused: report.files.filter((one) => one.state === "excused").map((one) => ({
86
- path: one.path,
87
- reason: "a contract-migration marker this gate could believe"
88
- })),
89
- findings: [...report.refusals, ...report.markers, ...report.squawk],
90
- read: report.files.filter((one) => one.state !== "excused" && one.state !== "unreadable").length,
91
- refused: report.unreadable.map((one) => ({ path: one.path, reason: one.why })),
92
- tool: MIGRATIONS_TOOL,
93
- version: versionOf(import.meta.url)
94
- });
31
+ runPlan,
32
+ runPublished,
33
+ runSchema,
34
+ runSnapshot,
35
+ schemaEnvelope,
36
+ sweepEnvelope,
37
+ sweepSmoke,
38
+ writeEnvelope
39
+ } from "./chunk-MZWAN6WT.js";
95
40
 
96
41
  // src/release-cli.ts
42
+ import { existsSync } from "fs";
43
+ import { join, resolve } from "path";
97
44
  var USAGE = `geonosis-release <command> [options]
98
45
 
99
46
  migrations --since <ref> [--dialect <name>] [--root <dir>] [--json]
@@ -110,6 +57,17 @@ var USAGE = `geonosis-release <command> [options]
110
57
 
111
58
  Exit 0 clean, 1 refusals, 2 the run could not be made.
112
59
 
60
+ schema [--root <dir>] [--json]
61
+
62
+ The wall no oxlint rule can see. Over every migration under every directory
63
+ geonosis.json \u2192 release.schema.domains declares: a statement naming a table another
64
+ domain declared is a cross-domain dependency the import graph does not show, and a
65
+ current_setting('\u2026') outside release.schema.sessionVariables writes one consumer's
66
+ session vocabulary into a package everyone installs.
67
+
68
+ Options only, empty defaults; the block declared and empty is a refusal naming both.
69
+ Whole-directory, not diff-scoped \u2014 a domain's migrations are applied as a set.
70
+
113
71
  plan [--root <dir>] [--i-accept-an-unproven-smoke] [--json]
114
72
 
115
73
  The contract as data \u2014 geonosis.json \u2192 release.steps and release.proof \u2014 validated
@@ -133,13 +91,88 @@ var USAGE = `geonosis-release <command> [options]
133
91
  tree declares in the wrangler configs geonosis.json names and release.secrets.
134
92
  \`versions upload\` applies no triggers, and a secret can be put outside the gate
135
93
  entirely \u2014 so declared and deployed drift apart silently, with a green pipeline.
94
+
95
+ published --group [--registry <url>] [--wait <seconds>] [--root <dir>] [--json]
96
+
97
+ Every workspace's local version against the version the registry answers, with no
98
+ sampling. \`changeset publish\` exiting zero is not the release; the GROUP resolving
99
+ from npm is \u2014 a six-package sample announced a version while the one unchecked entry
100
+ point read one release behind, and the consumer's bump aborted on it and left a
101
+ nested duplicate (#147).
102
+
103
+ The registry is asked over HTTP, never through npm or bun: their manifest CACHE is
104
+ the thing that lied. --wait polls through the few minutes in which a freshly
105
+ published name still 404s.
106
+
107
+ Exit 0 the whole group is there, 1 a gap, 2 the registry could not be asked.
108
+
109
+ adoption [--registry <url>] [--root <dir>] [--json]
110
+
111
+ How far every declared consumer is from the version this workspace holds, read off
112
+ the recordings the smoke keeps and never off a consumer's disk. Per consumer: MATCH,
113
+ BEHIND <name> <declared> \u2192 <current>, INCOHERENT (a group published as one number
114
+ declared at two), FLOOR UNDECLARED (informational \u2014 a floor is opted into).
115
+
116
+ --registry compares against what npm answers instead of against this workspace.
117
+
118
+ Exit 0 always: it is a report, and the release review carries one row per consumer
119
+ from it (D-061).
120
+
121
+ smoke snapshot <name> --from <their tree> [--replace] [--root <dir>] [--json]
122
+ [--typecheck <cmd>] [--lint <cmd>] [--doctor <cmd>]
123
+
124
+ Copy a consumer tree, read-only, into .geonosis/consumer-snapshots/<name>/ \u2014 the
125
+ thing a release must be read against. Installed packages, build output and the git
126
+ history stay behind; the manager comes off the lockfile; the versions every manifest
127
+ declares and the commands the smoke will run are recorded beside the copy.
128
+
129
+ The bytes are a private tree's (D-048), so it refuses to write where git would let
130
+ them be committed.
131
+
132
+ smoke baseline --snapshot <name> [--rc-dir <workspace>] [--install <cmd>] [--json]
133
+ smoke run [--snapshot <name>] [--absent <name>]... [--rc-dir <workspace>] [--install <cmd>]
134
+ [--json]
135
+
136
+ Pack every workspace package of the release candidate (\`pnpm pack\` \u2014 a tarball is
137
+ what a consumer installs, and a release that shipped no declarations shipped them in
138
+ the tree and not in the tarball), point a COPY of the snapshot's manifests at those
139
+ tarballs, install with the snapshot's own manager, and run the snapshot's own
140
+ typecheck, lint and doctor.
141
+
142
+ \`baseline\` records what those three answered at the versions the consumer is on.
143
+ \`run\` compares against it and refuses only what THIS release broke, in their
144
+ compiler's and their doctor's own lines. Exit 0 nothing new, 1 a new failure,
145
+ 2 the run could not be made \u2014 including a phase the baseline cannot be compared to.
146
+
147
+ With no --snapshot it sweeps every consumer geonosis.json declares, one block each in
148
+ declaration order. A declared name with no recording whose tree is on this machine \u2014
149
+ named in .geonosis/consumer-trees.local.json, uncommitted \u2014 REFUSES with the snapshot
150
+ command to run; --absent <name> excuses one out loud and keeps it in the count. A
151
+ recording whose source tree has moved since it was taken prints STALE.
136
152
  `;
137
- var VALUED = /* @__PURE__ */ new Set(["--dialect", "--root", "--runner", "--since"]);
138
- var FLAGS = /* @__PURE__ */ new Set(["--check", "--i-accept-an-unproven-smoke", "--json"]);
153
+ var VALUED = /* @__PURE__ */ new Set([
154
+ "--absent",
155
+ "--dialect",
156
+ "--doctor",
157
+ "--from",
158
+ "--install",
159
+ "--lint",
160
+ "--rc-dir",
161
+ "--registry",
162
+ "--root",
163
+ "--runner",
164
+ "--since",
165
+ "--snapshot",
166
+ "--typecheck",
167
+ "--wait"
168
+ ]);
169
+ var FLAGS = /* @__PURE__ */ new Set(["--check", "--group", "--i-accept-an-unproven-smoke", "--json", "--replace"]);
139
170
  var DIALECTS = /* @__PURE__ */ new Set(["mikro-orm-ts", "postgres", "sqlite"]);
140
171
  var parseArgs = (argv) => {
172
+ const many = {};
141
173
  const read = {};
142
174
  const flags = /* @__PURE__ */ new Set();
175
+ const rest = [];
143
176
  let json = false;
144
177
  for (let index = 1; index < argv.length; index += 1) {
145
178
  const flag = argv[index] ?? "";
@@ -148,13 +181,18 @@ var parseArgs = (argv) => {
148
181
  flags.add(flag);
149
182
  continue;
150
183
  }
184
+ if (!flag.startsWith("--")) {
185
+ rest.push(flag);
186
+ continue;
187
+ }
151
188
  if (!VALUED.has(flag)) throw new CannotRun(`unknown argument "${flag}"`);
152
189
  const value = argv[index + 1];
153
190
  if (value === void 0 || value.startsWith("--")) throw new CannotRun(`${flag} needs a value`);
154
191
  read[flag] = value;
192
+ many[flag] = [...many[flag] ?? [], value];
155
193
  index += 1;
156
194
  }
157
- return { command: argv[0] ?? "", flags, json, read };
195
+ return { command: argv[0] ?? "", flags, json, many, read, rest };
158
196
  };
159
197
  var rootOf = (parsed, cwd) => resolve(cwd, parsed.read["--root"] ?? cwd);
160
198
  var migrations = (parsed, cwd) => {
@@ -185,6 +223,24 @@ var migrations = (parsed, cwd) => {
185
223
  if (report.unreadable.length > 0) return 2;
186
224
  return report.ok ? 0 : 1;
187
225
  };
226
+ var schema = (parsed, cwd) => {
227
+ const root = rootOf(parsed, cwd);
228
+ const startedAt = Date.now();
229
+ const report = runSchema({ root });
230
+ process.stdout.write(
231
+ parsed.json ? `${JSON.stringify(report, void 0, 2)}
232
+ ` : formatSchema(report)
233
+ );
234
+ const at = writeEnvelope({
235
+ envelope: schemaEnvelope(report, Date.now() - startedAt),
236
+ next: SCHEMA_NEXT,
237
+ root
238
+ });
239
+ if (!parsed.json) process.stdout.write(`envelope: ${at}
240
+ `);
241
+ if (report.unreadable.length > 0) return 2;
242
+ return report.ok ? 0 : 1;
243
+ };
188
244
  var plan = (parsed, cwd) => {
189
245
  const report = runPlan({
190
246
  accept: parsed.flags.has("--i-accept-an-unproven-smoke"),
@@ -223,6 +279,166 @@ var deployed = (parsed, cwd) => {
223
279
  );
224
280
  return report.ok ? 0 : 1;
225
281
  };
282
+ var published = async (parsed, cwd) => {
283
+ if (!parsed.flags.has("--group")) {
284
+ throw new CannotRun("published needs --group \u2014 the whole workspace, or nothing");
285
+ }
286
+ const wait = parsed.read["--wait"];
287
+ if (wait !== void 0 && !/^\d+(?:\.\d+)?$/.test(wait)) {
288
+ throw new CannotRun(`--wait takes a number of seconds, not "${wait}"`);
289
+ }
290
+ const root = rootOf(parsed, cwd);
291
+ const startedAt = Date.now();
292
+ const report = await runPublished({
293
+ registry: parsed.read["--registry"] ?? DEFAULT_REGISTRY,
294
+ root,
295
+ waitSeconds: wait === void 0 ? 0 : Number(wait)
296
+ });
297
+ process.stdout.write(
298
+ parsed.json ? `${JSON.stringify(report, void 0, 2)}
299
+ ` : formatPublished(report)
300
+ );
301
+ const at = writeEnvelope({
302
+ envelope: publishedEnvelope(report, Date.now() - startedAt),
303
+ next: PUBLISHED_NEXT,
304
+ root
305
+ });
306
+ if (!parsed.json) process.stdout.write(`envelope: ${at}
307
+ `);
308
+ if (report.unreachable > 0) return 2;
309
+ return report.ok ? 0 : 1;
310
+ };
311
+ var adoption = async (parsed, cwd) => {
312
+ const root = rootOf(parsed, cwd);
313
+ const startedAt = Date.now();
314
+ const registry = parsed.read["--registry"];
315
+ const report = await runAdoption({
316
+ declared: readReleaseConfig(root).smoke?.snapshots ?? [],
317
+ ...registry === void 0 ? {} : { registry },
318
+ root
319
+ });
320
+ process.stdout.write(
321
+ parsed.json ? `${JSON.stringify(report, void 0, 2)}
322
+ ` : formatAdoption(report)
323
+ );
324
+ const at = writeEnvelope({
325
+ envelope: adoptionEnvelope(report, Date.now() - startedAt),
326
+ next: ADOPTION_NEXT,
327
+ root
328
+ });
329
+ if (!parsed.json) process.stdout.write(`envelope: ${at}
330
+ `);
331
+ return 0;
332
+ };
333
+ var namedCommands = (parsed) => ({
334
+ ...parsed.read["--doctor"] === void 0 ? {} : { doctor: parsed.read["--doctor"] },
335
+ ...parsed.read["--lint"] === void 0 ? {} : { lint: parsed.read["--lint"] },
336
+ ...parsed.read["--typecheck"] === void 0 ? {} : { typecheck: parsed.read["--typecheck"] }
337
+ });
338
+ var snapshot = (parsed, root) => {
339
+ const name = parsed.rest[1];
340
+ if (name === void 0) {
341
+ throw new CannotRun("smoke snapshot needs a name: smoke snapshot <name> --from <their tree>");
342
+ }
343
+ const from = parsed.read["--from"];
344
+ if (from === void 0) {
345
+ throw new CannotRun("smoke snapshot needs --from <the consumer tree to copy>");
346
+ }
347
+ const record = runSnapshot({
348
+ exclude: readReleaseConfig(root).smoke?.exclude ?? [],
349
+ from,
350
+ name,
351
+ named: namedCommands(parsed),
352
+ replace: parsed.flags.has("--replace"),
353
+ root
354
+ });
355
+ process.stdout.write(
356
+ parsed.json ? `${JSON.stringify(record, void 0, 2)}
357
+ ` : formatSnapshot(record)
358
+ );
359
+ return 0;
360
+ };
361
+ var wantedSnapshots = (parsed, root) => {
362
+ const configured = readReleaseConfig(root).smoke?.snapshots ?? [];
363
+ const named = parsed.read["--snapshot"];
364
+ const install = parsed.read["--install"];
365
+ const withFlag = (one) => {
366
+ const chosen = install ?? one.install;
367
+ return {
368
+ ...one.commands === void 0 ? {} : { commands: one.commands },
369
+ ...chosen === void 0 ? {} : { install: chosen },
370
+ name: one.name
371
+ };
372
+ };
373
+ if (named === void 0) return configured.map(withFlag);
374
+ return [withFlag(configured.find((one) => one.name === named) ?? { name: named })];
375
+ };
376
+ var rcOf = (parsed, root, cwd) => {
377
+ const named = parsed.read["--rc-dir"];
378
+ if (named !== void 0) return resolve(cwd, named);
379
+ if (existsSync(join(root, "package.json"))) return root;
380
+ throw new CannotRun(
381
+ "nothing here is a release candidate \u2014 pass --rc-dir <the workspace whose packages this release publishes>, because a smoke with nothing packed compares a tree to itself"
382
+ );
383
+ };
384
+ var baseline = (parsed, root, cwd) => {
385
+ const wanted = wantedSnapshots(parsed, root);
386
+ const one = wanted[0];
387
+ if (parsed.read["--snapshot"] === void 0 || one === void 0) {
388
+ throw new CannotRun("smoke baseline needs --snapshot <name>");
389
+ }
390
+ const rc = parsed.read["--rc-dir"];
391
+ const recorded = recordBaseline({
392
+ ...one.commands === void 0 ? {} : { commands: one.commands },
393
+ ...one.install === void 0 ? {} : { install: one.install },
394
+ name: one.name,
395
+ ...rc === void 0 ? {} : { rc: resolve(cwd, rc) },
396
+ root
397
+ });
398
+ process.stdout.write(
399
+ parsed.json ? `${JSON.stringify(recorded, void 0, 2)}
400
+ ` : formatBaseline(one.name, recorded)
401
+ );
402
+ return 0;
403
+ };
404
+ var smokeRun = (parsed, root, cwd) => {
405
+ const startedAt = Date.now();
406
+ const wanted = wantedSnapshots(parsed, root);
407
+ if (wanted.length === 0) {
408
+ throw new CannotRun(
409
+ "nothing here names a consumer to read this release against \u2014 geonosis.json \u2192 release.smoke.snapshots names them, or pass --snapshot <name>. A release check over zero consumers is not a green release check."
410
+ );
411
+ }
412
+ const swept = sweepSmoke({
413
+ absent: parsed.many["--absent"] ?? [],
414
+ rc: rcOf(parsed, root, cwd),
415
+ root,
416
+ skipMissing: parsed.read["--snapshot"] === void 0,
417
+ wanted
418
+ });
419
+ process.stdout.write(
420
+ parsed.json ? `${JSON.stringify(swept, void 0, 2)}
421
+ ` : formatSweep(swept)
422
+ );
423
+ const at = writeEnvelope({
424
+ envelope: sweepEnvelope(swept, Date.now() - startedAt),
425
+ next: SMOKE_NEXT,
426
+ root
427
+ });
428
+ if (!parsed.json) process.stdout.write(`envelope: ${at}
429
+ `);
430
+ const comparisons = comparisonsIn(swept);
431
+ if (comparisons.some((one) => one.refused.length > 0)) return 2;
432
+ return comparisons.every((one) => one.ok) ? 0 : 1;
433
+ };
434
+ var smoke = (parsed, cwd) => {
435
+ const root = rootOf(parsed, cwd);
436
+ const verb = parsed.rest[0];
437
+ if (verb === "snapshot") return snapshot(parsed, root);
438
+ if (verb === "baseline") return baseline(parsed, root, cwd);
439
+ if (verb === "run") return smokeRun(parsed, root, cwd);
440
+ throw new CannotRun(`smoke has snapshot, baseline and run \u2014 "${verb ?? ""}" is none of them`);
441
+ };
226
442
  var CONFIG_SHAPE = `geonosis-release reads geonosis.json
227
443
 
228
444
  geonosis.json \u2192 "release" every key optional; a repo that configured nothing gets nothing
@@ -232,6 +448,15 @@ geonosis.json \u2192 "release" every key optional; a repo that configured n
232
448
  phases string[]? "up" and/or "down" (default ["up"])
233
449
  squawk object? { exclude: string[] } \u2014 the rule ids to leave out
234
450
  proof object? { mustAssertVersion: boolean }
451
+ schema object? the walls no oxlint rule can see (#168)
452
+ domains Entry[]? { dir, name, tables } \u2014 whose migrations, and whose tables
453
+ sessionVariables string[]? the session variable names DDL may name
454
+ smoke object? the consumer trees this release is read against
455
+ exclude string[]? what a snapshot leaves behind, beyond the built and the installed
456
+ snapshots Entry[]? { name, install?, commands? } \u2014 the recorded snapshot, the command
457
+ that tree is installed with when the manager's default is not it,
458
+ and { doctor?, lint?, typecheck? } when their gates are not the
459
+ scripts of those names
235
460
  secrets string[]? the secret names a deployment carries
236
461
  steps string[]? the release steps
237
462
  workers string[]? the workers it deploys
@@ -239,7 +464,10 @@ geonosis.json \u2192 "release" every key optional; a repo that configured n
239
464
  wranglerEnv string? the named environment block to read out of them
240
465
 
241
466
  A key outside either list is refused BY NAME, with the accepted set. This shape had to be read out
242
- of a bundled chunk file by a consumer once (#75).`;
467
+ of a bundled chunk file by a consumer once (#75).
468
+
469
+ published reads no geonosis.json at all: its inputs are every package.json under the root \u2014 "name"
470
+ and "version", and "private" to tell a package a publish is a claim about from one it is not.`;
243
471
  var main = async () => {
244
472
  const argv = process.argv.slice(2);
245
473
  if (argv.includes("--print-config-shape")) {
@@ -252,12 +480,18 @@ var main = async () => {
252
480
  return 0;
253
481
  }
254
482
  const parsed = parseArgs(argv);
483
+ if (parsed.command === "smoke") return smoke(parsed, process.cwd());
484
+ const stray = parsed.rest[0];
485
+ if (stray !== void 0) throw new CannotRun(`unknown argument "${stray}"`);
255
486
  if (parsed.command === "migrations") return migrations(parsed, process.cwd());
256
487
  if (parsed.command === "plan") return plan(parsed, process.cwd());
488
+ if (parsed.command === "schema") return schema(parsed, process.cwd());
257
489
  if (parsed.command === "prove") return proving(parsed, process.cwd());
258
490
  if (parsed.command === "deployed") return deployed(parsed, process.cwd());
491
+ if (parsed.command === "published") return published(parsed, process.cwd());
492
+ if (parsed.command === "adoption") return adoption(parsed, process.cwd());
259
493
  throw new CannotRun(
260
- `no command called "${parsed.command}" \u2014 this bin has migrations, plan, prove, deployed`
494
+ `no command called "${parsed.command}" \u2014 this bin has migrations, schema, plan, prove, deployed, published, adoption, smoke`
261
495
  );
262
496
  };
263
497
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geonosis/release",
3
- "version": "1.4.0",
3
+ "version": "2.1.0",
4
4
  "types": "./dist/index.d.ts",
5
5
  "description": "The release contract with its proofs: an expand-only migration gate over three dialects, a smoke that must name the version that answered it, and declared ≠ deployed.",
6
6
  "keywords": [
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "devDependencies": {
47
47
  "squawk-cli": "2.63.0",
48
- "@geonosis/ratchet": "1.4.0"
48
+ "@geonosis/ratchet": "2.1.0"
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=22"