automata-cli 0.8.0-develop.358 → 0.8.1

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 (2) hide show
  1. package/dist/index.js +57 -20
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1175,6 +1175,32 @@ function resolveReleaseVersion(requested, trunkRef, latestTag) {
1175
1175
  return { ok: true, version: version2, notice: `Auto-detected version: ${latest} \u2192 ${version2}` };
1176
1176
  }
1177
1177
 
1178
+ // src/git/changelogGate.ts
1179
+ import { readFileSync as readFileSync2 } from "fs";
1180
+ import { join } from "path";
1181
+ var CHANGELOG_FILE = "CHANGELOG.md";
1182
+ var VERSION_HEADING = /^## \[(\d+\.\d+\.\d+)\] - \d{4}-\d{2}-\d{2}$/;
1183
+ function checkChangelogSection(version2, changelog) {
1184
+ if (changelog === null) {
1185
+ return { ok: true };
1186
+ }
1187
+ const documented = changelog.split("\n").map((line) => VERSION_HEADING.exec(line.trimEnd())).some((match) => match !== null && match[1] === version2);
1188
+ if (documented) {
1189
+ return { ok: true };
1190
+ }
1191
+ return {
1192
+ ok: false,
1193
+ message: `${CHANGELOG_FILE} has no section for ${version2}. Add a '## [${version2}] - YYYY-MM-DD' heading \u2014 rename the current '## [Unreleased]' heading to it and open a fresh, empty '## [Unreleased]' above \u2014 then commit and re-run. See docs/maintenance.md#what-a-release-does-to-it.`
1194
+ };
1195
+ }
1196
+ function readChangelog(dir = process.cwd()) {
1197
+ try {
1198
+ return readFileSync2(join(dir, CHANGELOG_FILE), "utf8");
1199
+ } catch {
1200
+ return null;
1201
+ }
1202
+ }
1203
+
1178
1204
  // src/commands/git.ts
1179
1205
  var FAIL_CONCLUSIONS = /* @__PURE__ */ new Set(["FAILURE", "TIMED_OUT", "ACTION_REQUIRED", "CANCELLED"]);
1180
1206
  var SKIP_CONCLUSIONS = /* @__PURE__ */ new Set(["SKIPPED", "NEUTRAL"]);
@@ -1556,7 +1582,12 @@ Tags are fetched from origin first, in --dry-run too, so the version a dry run
1556
1582
  prints is the one a real run would use.
1557
1583
 
1558
1584
  When [version] is omitted the latest semver tag on origin/<trunk> is detected
1559
- and the minor segment is incremented (e.g. 1.2.0 \u2192 1.3.0).`
1585
+ and the minor segment is incremented (e.g. 1.2.0 \u2192 1.3.0).
1586
+
1587
+ CHANGELOG.md must already carry a '## [<version>] - YYYY-MM-DD' section for the
1588
+ version being released; the release is refused otherwise, in --dry-run too, and
1589
+ before any branch, merge or tag is created. A repository with no CHANGELOG.md is
1590
+ not subject to the check.`
1560
1591
  ).action((version2, options) => {
1561
1592
  const dryRun = options.dryRun ?? false;
1562
1593
  const preconditions = checkReleasePreconditions();
@@ -1595,6 +1626,12 @@ ${fetched.message}
1595
1626
  }
1596
1627
  if (tagExists(resolvedVersion)) {
1597
1628
  process.stderr.write(`Error: Tag '${resolvedVersion}' already exists.
1629
+ `);
1630
+ process.exit(1);
1631
+ }
1632
+ const changelog = checkChangelogSection(resolvedVersion, readChangelog());
1633
+ if (!changelog.ok) {
1634
+ process.stderr.write(`Error: ${changelog.message}
1598
1635
  `);
1599
1636
  process.exit(1);
1600
1637
  }
@@ -2243,11 +2280,11 @@ import { createInterface } from "readline";
2243
2280
 
2244
2281
  // src/cli/spawnUtils.ts
2245
2282
  import { accessSync, constants, statSync } from "fs";
2246
- import { delimiter, join } from "path";
2283
+ import { delimiter, join as join2 } from "path";
2247
2284
  function resolveCommand(name) {
2248
2285
  const pathDirs = (process.env["PATH"] ?? "").split(delimiter);
2249
2286
  for (const dir of pathDirs) {
2250
- const candidate = join(dir, name);
2287
+ const candidate = join2(dir, name);
2251
2288
  if (isLaunchable(candidate)) return candidate;
2252
2289
  }
2253
2290
  return name;
@@ -2766,7 +2803,7 @@ function linkPrToIssue(issueNumber, commentUrl, askCopilotReview, agentUser) {
2766
2803
  }
2767
2804
 
2768
2805
  // src/commands/execute.ts
2769
- import { readFileSync as readFileSync2 } from "fs";
2806
+ import { readFileSync as readFileSync3 } from "fs";
2770
2807
  import { Command as Command4 } from "commander";
2771
2808
  function readStdin() {
2772
2809
  return new Promise((resolve2, reject) => {
@@ -2789,7 +2826,7 @@ async function resolvePrompt(options) {
2789
2826
  if (hasFile) {
2790
2827
  const path = options.filePrompt;
2791
2828
  try {
2792
- return readFileSync2(path, "utf8");
2829
+ return readFileSync3(path, "utf8");
2793
2830
  } catch {
2794
2831
  process.stderr.write(`Error: Cannot read file: ${path}
2795
2832
  `);
@@ -3629,19 +3666,19 @@ function analyseAnswer(messages, p, marker, watermark) {
3629
3666
  }
3630
3667
 
3631
3668
  // src/run/runLock.ts
3632
- import { writeFileSync, readFileSync as readFileSync3, unlinkSync, mkdirSync, renameSync, linkSync, statSync as statSync2 } from "fs";
3669
+ import { writeFileSync, readFileSync as readFileSync4, unlinkSync, mkdirSync, renameSync, linkSync, statSync as statSync2 } from "fs";
3633
3670
  import { randomUUID } from "crypto";
3634
3671
  import { hostname } from "os";
3635
- import { join as join2 } from "path";
3672
+ import { join as join3 } from "path";
3636
3673
  var LOCK_DIR = ".automata";
3637
3674
  var LOCK_FILE = "automata.lock";
3638
3675
  var RUN_LOCK_RELATIVE_PATH = `${LOCK_DIR}/${LOCK_FILE}`;
3639
3676
  function lockPath() {
3640
- return join2(process.cwd(), LOCK_DIR, LOCK_FILE);
3677
+ return join3(process.cwd(), LOCK_DIR, LOCK_FILE);
3641
3678
  }
3642
3679
  function processStartedAt(pid) {
3643
3680
  try {
3644
- const stat = readFileSync3(`/proc/${String(pid)}/stat`, "utf8");
3681
+ const stat = readFileSync4(`/proc/${String(pid)}/stat`, "utf8");
3645
3682
  const afterComm = stat.slice(stat.lastIndexOf(")") + 2);
3646
3683
  const field = afterComm.split(" ")[19];
3647
3684
  return field === void 0 || field.length === 0 ? null : field;
@@ -3659,7 +3696,7 @@ function isAlive(pid) {
3659
3696
  }
3660
3697
  function readOwnerError(path) {
3661
3698
  try {
3662
- readFileSync3(path, "utf8");
3699
+ readFileSync4(path, "utf8");
3663
3700
  return null;
3664
3701
  } catch (err) {
3665
3702
  return err.message;
@@ -3667,7 +3704,7 @@ function readOwnerError(path) {
3667
3704
  }
3668
3705
  function readOwner(path) {
3669
3706
  try {
3670
- const parsed = JSON.parse(readFileSync3(path, "utf8"));
3707
+ const parsed = JSON.parse(readFileSync4(path, "utf8"));
3671
3708
  if (typeof parsed.pid !== "number" || typeof parsed.startedAt !== "string") return null;
3672
3709
  return {
3673
3710
  pid: parsed.pid,
@@ -3768,7 +3805,7 @@ function publishLock(path, command, token) {
3768
3805
  function acquireRunLock(command, staleMinutes) {
3769
3806
  const path = lockPath();
3770
3807
  const token = randomUUID();
3771
- mkdirSync(join2(process.cwd(), LOCK_DIR), { recursive: true });
3808
+ mkdirSync(join3(process.cwd(), LOCK_DIR), { recursive: true });
3772
3809
  if (publishLock(path, command, token)) {
3773
3810
  return { ok: true, handle: makeHandle(path, token) };
3774
3811
  }
@@ -3846,7 +3883,7 @@ function acquireClaim(path) {
3846
3883
  function claimIsAbandoned(claimPath) {
3847
3884
  let at = Number.NaN;
3848
3885
  try {
3849
- const raw = JSON.parse(readFileSync3(claimPath, "utf8"));
3886
+ const raw = JSON.parse(readFileSync4(claimPath, "utf8"));
3850
3887
  if (raw.at !== void 0) at = Date.parse(raw.at);
3851
3888
  } catch {
3852
3889
  }
@@ -4385,13 +4422,13 @@ import {
4385
4422
  accessSync as accessSync2,
4386
4423
  appendFileSync,
4387
4424
  constants as constants2,
4388
- readFileSync as readFileSync4,
4425
+ readFileSync as readFileSync5,
4389
4426
  renameSync as renameSync2,
4390
4427
  unlinkSync as unlinkSync2,
4391
4428
  writeFileSync as writeFileSync2
4392
4429
  } from "fs";
4393
4430
  import { randomUUID as randomUUID2 } from "crypto";
4394
- import { dirname as dirname2, join as join3 } from "path";
4431
+ import { dirname as dirname2, join as join4 } from "path";
4395
4432
  var EXECUTION_LOG_FILE = "automata-execution.log";
4396
4433
  var WORK_LOG_FILE = "automata-work.log";
4397
4434
  var MAX_EXECUTION_LINES = 1e3;
@@ -4513,9 +4550,9 @@ function pruneOldRecords(content, now, maxAgeMs) {
4513
4550
  }).map((group) => group.lines.join("\n") + "\n").join("");
4514
4551
  }
4515
4552
  function appendWithRetention(dir, file, content, retain) {
4516
- const target = join3(dir, file);
4553
+ const target = join4(dir, file);
4517
4554
  appendFileSync(target, content, "utf8");
4518
- const existing = readFileSync4(target, "utf8");
4555
+ const existing = readFileSync5(target, "utf8");
4519
4556
  const retained = retain(existing);
4520
4557
  if (retained === existing) return;
4521
4558
  const temp = `${target}.${randomUUID2()}.tmp`;
@@ -4562,7 +4599,7 @@ function isOutcome(value) {
4562
4599
  }
4563
4600
  function readLogFile(path) {
4564
4601
  try {
4565
- return { content: readFileSync4(path, "utf8"), error: null };
4602
+ return { content: readFileSync5(path, "utf8"), error: null };
4566
4603
  } catch (err) {
4567
4604
  if (err.code === "ENOENT") return { content: null, error: null };
4568
4605
  return { content: null, error: err.message };
@@ -4628,7 +4665,7 @@ function parseExecutionLine(line) {
4628
4665
  };
4629
4666
  }
4630
4667
  function readExecutionTicks(options = {}) {
4631
- const path = join3(options.dir ?? operationLogDirectory(), EXECUTION_LOG_FILE);
4668
+ const path = join4(options.dir ?? operationLogDirectory(), EXECUTION_LOG_FILE);
4632
4669
  const { content, error } = readLogFile(path);
4633
4670
  if (content === null) return emptyResult(path, error, isFiltered(options.repo));
4634
4671
  const entries = [];
@@ -4690,7 +4727,7 @@ function parseWorkItem(line) {
4690
4727
  };
4691
4728
  }
4692
4729
  function readWorkRecords(options = {}) {
4693
- const path = join3(options.dir ?? operationLogDirectory(), WORK_LOG_FILE);
4730
+ const path = join4(options.dir ?? operationLogDirectory(), WORK_LOG_FILE);
4694
4731
  const { content, error } = readLogFile(path);
4695
4732
  if (content === null) return emptyResult(path, error, isFiltered(options.repo));
4696
4733
  const entries = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "automata-cli",
3
- "version": "0.8.0-develop.358",
3
+ "version": "0.8.1",
4
4
  "description": "Automata CLI tool",
5
5
  "type": "module",
6
6
  "engines": {