@astra-kit/rp 0.0.0-stage → 0.10.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 (125) hide show
  1. package/CHANGELOG.md +196 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +352 -2
  4. package/bin/astra-rp.js +51 -0
  5. package/package.json +93 -4
  6. package/src/build-gate.js +157 -0
  7. package/src/changelog-blocks.js +53 -0
  8. package/src/changelog.js +108 -0
  9. package/src/constants/build-gate.js +30 -0
  10. package/src/constants/changelog-draft.js +180 -0
  11. package/src/constants/changelog.js +74 -0
  12. package/src/constants/ci-release.js +346 -0
  13. package/src/constants/cli.js +12 -0
  14. package/src/constants/create-version.js +523 -0
  15. package/src/constants/guard-publish.js +29 -0
  16. package/src/constants/index.js +18 -0
  17. package/src/constants/monorepo.js +57 -0
  18. package/src/constants/package-manager.js +56 -0
  19. package/src/constants/registry.js +72 -0
  20. package/src/constants/terminal-ui.js +93 -0
  21. package/src/constants/version-files.js +63 -0
  22. package/src/constants/versions.js +60 -0
  23. package/src/create-version/artifact.js +343 -0
  24. package/src/create-version/changelog-draft-workspace.js +124 -0
  25. package/src/create-version/changelog-draft.js +380 -0
  26. package/src/create-version/changelog.js +264 -0
  27. package/src/create-version/ci-config.js +54 -0
  28. package/src/create-version/ci-publication-history.js +113 -0
  29. package/src/create-version/ci-release-identity-step.js +58 -0
  30. package/src/create-version/ci-setup.js +794 -0
  31. package/src/create-version/ci.js +555 -0
  32. package/src/create-version/committed-tree.js +75 -0
  33. package/src/create-version/config.js +489 -0
  34. package/src/create-version/errors.js +46 -0
  35. package/src/create-version/github-workflow.js +199 -0
  36. package/src/create-version/index.js +54 -0
  37. package/src/create-version/json.js +32 -0
  38. package/src/create-version/jsonc.js +76 -0
  39. package/src/create-version/jsr.js +96 -0
  40. package/src/create-version/local-changes.js +178 -0
  41. package/src/create-version/npm-auth.js +142 -0
  42. package/src/create-version/npm.js +812 -0
  43. package/src/create-version/plan.js +1200 -0
  44. package/src/create-version/process.js +334 -0
  45. package/src/create-version/registry-config.js +121 -0
  46. package/src/create-version/registry-http.js +62 -0
  47. package/src/create-version/registry.js +220 -0
  48. package/src/create-version/release-execution.js +45 -0
  49. package/src/create-version/release-tag-config.js +76 -0
  50. package/src/create-version/run.js +2087 -0
  51. package/src/create-version/state.js +461 -0
  52. package/src/create-version/strict-utf8.js +11 -0
  53. package/src/create-version/templates/release.yml +52 -0
  54. package/src/create-version/templates/vercel-ignore-build.mjs +66 -0
  55. package/src/guard-publish.js +77 -0
  56. package/src/index.js +42 -0
  57. package/src/monorepo/plan.js +475 -0
  58. package/src/monorepo/release-commit.js +46 -0
  59. package/src/monorepo/run.js +927 -0
  60. package/src/monorepo/state.js +206 -0
  61. package/src/monorepo/workspaces.js +327 -0
  62. package/src/package-manager.js +107 -0
  63. package/src/terminal-ui.js +548 -0
  64. package/src/testing.js +70 -0
  65. package/src/version-files.js +142 -0
  66. package/src/versions.js +303 -0
  67. package/types/build-gate.d.ts +43 -0
  68. package/types/changelog-blocks.d.ts +33 -0
  69. package/types/changelog.d.ts +61 -0
  70. package/types/constants/build-gate.d.ts +23 -0
  71. package/types/constants/changelog-draft.d.ts +138 -0
  72. package/types/constants/changelog.d.ts +56 -0
  73. package/types/constants/ci-release.d.ts +284 -0
  74. package/types/constants/cli.d.ts +11 -0
  75. package/types/constants/create-version.d.ts +397 -0
  76. package/types/constants/guard-publish.d.ts +25 -0
  77. package/types/constants/index.d.ts +17 -0
  78. package/types/constants/monorepo.d.ts +45 -0
  79. package/types/constants/package-manager.d.ts +40 -0
  80. package/types/constants/registry.d.ts +79 -0
  81. package/types/constants/terminal-ui.d.ts +73 -0
  82. package/types/constants/version-files.d.ts +51 -0
  83. package/types/constants/versions.d.ts +47 -0
  84. package/types/create-version/artifact.d.ts +113 -0
  85. package/types/create-version/changelog-draft-workspace.d.ts +33 -0
  86. package/types/create-version/changelog-draft.d.ts +127 -0
  87. package/types/create-version/changelog.d.ts +141 -0
  88. package/types/create-version/ci-config.d.ts +33 -0
  89. package/types/create-version/ci-publication-history.d.ts +51 -0
  90. package/types/create-version/ci-release-identity-step.d.ts +12 -0
  91. package/types/create-version/ci-setup.d.ts +148 -0
  92. package/types/create-version/ci.d.ts +145 -0
  93. package/types/create-version/committed-tree.d.ts +55 -0
  94. package/types/create-version/config.d.ts +128 -0
  95. package/types/create-version/errors.d.ts +39 -0
  96. package/types/create-version/github-workflow.d.ts +41 -0
  97. package/types/create-version/index.d.ts +28 -0
  98. package/types/create-version/json.d.ts +21 -0
  99. package/types/create-version/jsonc.d.ts +21 -0
  100. package/types/create-version/jsr.d.ts +52 -0
  101. package/types/create-version/local-changes.d.ts +52 -0
  102. package/types/create-version/npm-auth.d.ts +60 -0
  103. package/types/create-version/npm.d.ts +331 -0
  104. package/types/create-version/plan.d.ts +369 -0
  105. package/types/create-version/process.d.ts +151 -0
  106. package/types/create-version/registry-config.d.ts +56 -0
  107. package/types/create-version/registry-http.d.ts +22 -0
  108. package/types/create-version/registry.d.ts +86 -0
  109. package/types/create-version/release-execution.d.ts +22 -0
  110. package/types/create-version/release-tag-config.d.ts +18 -0
  111. package/types/create-version/run.d.ts +407 -0
  112. package/types/create-version/state.d.ts +204 -0
  113. package/types/create-version/strict-utf8.d.ts +10 -0
  114. package/types/guard-publish.d.ts +49 -0
  115. package/types/index.d.ts +23 -0
  116. package/types/monorepo/plan.d.ts +68 -0
  117. package/types/monorepo/release-commit.d.ts +29 -0
  118. package/types/monorepo/run.d.ts +68 -0
  119. package/types/monorepo/state.d.ts +96 -0
  120. package/types/monorepo/workspaces.d.ts +86 -0
  121. package/types/package-manager.d.ts +58 -0
  122. package/types/terminal-ui.d.ts +196 -0
  123. package/types/testing.d.ts +31 -0
  124. package/types/version-files.d.ts +59 -0
  125. package/types/versions.d.ts +158 -0
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Layout, ANSI and key contracts of the dependency-free terminal UI.
3
+ *
4
+ * @module constants/terminal-ui
5
+ */
6
+ /** Widest box drawn, so lines stay readable on large terminals. */
7
+ export declare const MAX_BOX_WIDTH = 84;
8
+ /** Width assumed when stdout does not report its columns. */
9
+ export declare const FALLBACK_TERMINAL_WIDTH = 80;
10
+ /** Columns kept free at the right of the terminal when sizing a box. */
11
+ export declare const TERMINAL_RIGHT_MARGIN = 2;
12
+ /** Horizontal padding inside a box, per side. */
13
+ export declare const BOX_PADDING = 1;
14
+ /** Width of the label column of status rows. */
15
+ export declare const ROW_LABEL_WIDTH = 16;
16
+ /** Spinner animation frames. */
17
+ export declare const SPINNER_FRAMES: readonly string[];
18
+ /** Delay between spinner frames. */
19
+ export declare const SPINNER_INTERVAL_MS = 80;
20
+ /** Exit code conventionally used after Ctrl+C. */
21
+ export declare const INTERRUPTED_EXIT_CODE = 130;
22
+ /** Splits styled text into ANSI escape sequences and single code points. */
23
+ export declare const ANSI_TOKEN_PATTERN: RegExp;
24
+ /** First character of every ANSI escape sequence. */
25
+ export declare const ANSI_ESCAPE = "\u001B";
26
+ /** ANSI control sequences used by boxes, spinners and prompts. */
27
+ export declare const ANSI_SEQUENCE: Readonly<{
28
+ reset: "\u001B[0m";
29
+ hideCursor: "\u001B[?25l";
30
+ showCursor: "\u001B[?25h";
31
+ clearLine: "\r\u001B[2K";
32
+ clearBelow: "\u001B[0J";
33
+ }>;
34
+ /** Border color of each box tone. */
35
+ export declare const BOX_TONE: Readonly<{
36
+ neutral: "gray";
37
+ info: "cyan";
38
+ success: "green";
39
+ warning: "yellow";
40
+ danger: "red";
41
+ accent: "magenta";
42
+ }>;
43
+ /** Nerd Font glyphs (Font Awesome and Octicons sets) used as status icons. */
44
+ export declare const ICON_GLYPH: Readonly<{
45
+ success: "";
46
+ failure: "";
47
+ warning: "";
48
+ info: "";
49
+ pending: "";
50
+ arrow: "";
51
+ bullet: "";
52
+ star: "";
53
+ rocket: "";
54
+ }>;
55
+ /** Label/value rows (`renderRow`): the value starts after a gap of two or more spaces. */
56
+ export declare const VALUE_COLUMN_PATTERN: RegExp;
57
+ /** Leading marker (icon, arrow, bullet or `1.`, never a word) followed by a space, used as hanging indent. */
58
+ export declare const HANGING_MARKER_PATTERN: RegExp;
59
+ /** Options that can be picked with a single digit key (1-9). */
60
+ export declare const MAX_NUMBERED_OPTIONS = 9;
61
+ /** A single digit key that picks a numbered option. */
62
+ export declare const NUMBER_KEY_PATTERN: RegExp;
63
+ /** Seconds in a minute, used to format durations. */
64
+ export declare const SECONDS_PER_MINUTE = 60;
65
+ /** Milliseconds in a second, used to format durations. */
66
+ export declare const MILLISECONDS_PER_SECOND = 1000;
67
+ /** Key names (`readline` keypress events) handled by the select prompt. */
68
+ export declare const PROMPT_KEY: Readonly<{
69
+ interrupt: "c";
70
+ previous: readonly string[];
71
+ next: readonly string[];
72
+ confirm: readonly string[];
73
+ }>;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Markers of `versionFiles`: lines and blocks whose version `create-version`
3
+ * rewrites in the release commit, besides `package.json`.
4
+ *
5
+ * @module constants/version-files
6
+ */
7
+ /**
8
+ * Comment marking a single line whose version is rewritten. The release-please marker is also
9
+ * accepted, so a project moving from release-please keeps its files untouched.
10
+ */
11
+ export declare const VERSION_LINE_MARKERS: readonly string[];
12
+ /** Comments opening a block whose every version is rewritten, paired by index with {@link VERSION_BLOCK_END_MARKERS}. */
13
+ export declare const VERSION_BLOCK_START_MARKERS: readonly string[];
14
+ /** Comments closing a version block, paired by index with {@link VERSION_BLOCK_START_MARKERS}. */
15
+ export declare const VERSION_BLOCK_END_MARKERS: readonly string[];
16
+ /**
17
+ * Ways a file can pair its version block markers wrongly. Any of them stops the rewrite, since
18
+ * guessing where a block ends could rewrite versions outside the intended section.
19
+ *
20
+ * - `unterminated`: a start marker without its end marker before the end of the file.
21
+ * - `unopened`: an end marker outside any block.
22
+ * - `nested`: a start marker inside a block that is still open.
23
+ * - `mismatched`: an end marker of the other tool (`x-release-please-end` closing `astra-rp-start-version`, or the reverse).
24
+ */
25
+ export declare const VERSION_BLOCK_PROBLEM: Readonly<{
26
+ unterminated: "unterminated";
27
+ unopened: "unopened";
28
+ nested: "nested";
29
+ mismatched: "mismatched";
30
+ }>;
31
+ /**
32
+ * A semantic version inside a marked line (`1.2.3`, `1.2.3-beta.1`, `1.2.3+build`), not glued to
33
+ * other version-like digits (`10.0.0.1`, `1.2.3.4`). A period that ends a sentence (`is 1.2.3.`)
34
+ * is not part of the version and is kept. Global: every version of a marked line is rewritten.
35
+ */
36
+ export declare const MARKED_VERSION_PATTERN: RegExp;
37
+ /**
38
+ * Splits a versioned file into lines right after each terminator (`\r\n`, `\n` or a lone `\r`),
39
+ * so every line keeps its own terminator and joining the lines gives back the original content.
40
+ */
41
+ export declare const LINE_TERMINATOR_BOUNDARY_PATTERN: RegExp;
42
+ /**
43
+ * Files the release owns: the bumped `package.json` and the CHANGELOG whose `[Unreleased]` it closes.
44
+ * `versionFiles` cannot list either: rewriting them would undo the bump or the closed section.
45
+ */
46
+ export declare const RELEASE_COMMIT_BUILT_IN_FILES: readonly string[];
47
+ /**
48
+ * Git pathspec magic that matches a configured path literally, so names starting with `:` or
49
+ * holding `*`/`?` are never read as pathspec syntax.
50
+ */
51
+ export declare const GIT_LITERAL_PATHSPEC_PREFIX = ":(literal)";
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Release version rules shared by `create-version` and the Vercel build gate.
3
+ *
4
+ * @module constants/versions
5
+ */
6
+ /** Semver release types, from the smallest to the largest change. */
7
+ export declare const RELEASE_TYPE: Readonly<{
8
+ patch: "patch";
9
+ minor: "minor";
10
+ major: "major";
11
+ }>;
12
+ /**
13
+ * Suggested release type before `1.0.0` with `preMajorShift`: one level down, the `0.x` convention
14
+ * where a minor carries breaking changes and a patch carries features (release-please's
15
+ * `bump-minor-pre-major` plus `bump-patch-for-minor-pre-major`).
16
+ */
17
+ export declare const PRE_MAJOR_SHIFTED_RELEASE_TYPE: Readonly<{
18
+ patch: "patch";
19
+ minor: "patch";
20
+ major: "minor";
21
+ }>;
22
+ /** Major version of the `0.x` line, where `preMajorShift` applies. */
23
+ export declare const PRE_MAJOR_VERSION = 0;
24
+ /**
25
+ * Version of a package that was never released (the release-please placeholder): the commit that
26
+ * sets it is not a release, and its first release keeps the unshifted suggestion (a feature gives
27
+ * `0.1.0`, not `0.0.1`).
28
+ */
29
+ export declare const UNRELEASED_PLACEHOLDER_VERSION = "0.0.0";
30
+ /** Release types in the order they are offered: patch, minor, major. */
31
+ export declare const RELEASE_TYPE_ORDER: readonly ("major" | "minor" | "patch")[];
32
+ /** Stable `X.Y.Z` release version: no prerelease, build metadata, prefix or leading zeros. */
33
+ export declare const RELEASE_VERSION_PATTERN: RegExp;
34
+ /** Any semver version, capturing its `X.Y.Z` core and optional prerelease. */
35
+ export declare const SEMVER_PATTERN: RegExp;
36
+ /** Prefix of the annotated Git tags that mark each release (`v0.93.0`). */
37
+ export declare const RELEASE_TAG_PREFIX = "v";
38
+ /** `git log --grep` pattern of release commit subjects (`0.93.0`). */
39
+ export declare const RELEASE_COMMIT_SUBJECT_GREP: string;
40
+ /** Conventional commit header: `type(scope)!: subject`. */
41
+ export declare const CONVENTIONAL_HEADER_PATTERN: RegExp;
42
+ /** Footer that marks a breaking change in a conventional commit body. */
43
+ export declare const BREAKING_CHANGE_FOOTER_PATTERN: RegExp;
44
+ /** Conventional commit type that ships user-visible features. */
45
+ export declare const FEATURE_COMMIT_TYPE = "feat";
46
+ /** Imperative verbs used by legacy, non-conventional feature subjects. */
47
+ export declare const LEGACY_FEATURE_SUBJECT_PATTERN: RegExp;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Locates and verifies the package archive prepared for a release, so
3
+ * `publish: "npm"` publishes exactly the artifact the project verified
4
+ * instead of repacking the working tree.
5
+ *
6
+ * Patterns are relative to the repository root, use `/` separators and
7
+ * replace `{version}` and `{name}` (the tarball base name `npm pack` uses, so
8
+ * `@scope/pkg` becomes `scope-pkg`). Inside a single path segment, `*` matches
9
+ * anything and `{sha256}` matches a SHA-256 digest that must equal the
10
+ * archive checksum (for example `releases/{version}-{sha256}/{name}-{version}.tgz`).
11
+ * `{sha256}` may repeat, in one segment or several: every occurrence must
12
+ * declare the same digest.
13
+ *
14
+ * Projects pack with `npm pack --ignore-scripts`, which is reproducible: the same
15
+ * checkout always yields the same bytes. So the archive is verified by comparing
16
+ * its SHA-512 integrity with the one `npm pack --dry-run` reports for the release
17
+ * checkout, and the manifest must not rely on rewrites only pnpm applies when packing.
18
+ * The archive is moved out of the package root during that dry run, so npm never
19
+ * counts it as part of the package it describes.
20
+ *
21
+ * @module create-version/artifact
22
+ */
23
+ export type PreparedArtifact = {
24
+ path: string;
25
+ expectedSha256: string | null;
26
+ };
27
+ export type PackageManifest = Record<string, unknown>;
28
+ /**
29
+ * Replaces the `{version}` and `{name}` placeholders of an artifact pattern; `{sha256}` stays.
30
+ * `{name}` becomes the tarball base name, so scoped packages never add a path separator.
31
+ *
32
+ * @param {string} pattern - Configured pattern.
33
+ * @param {{ version: string, packageName: string }} release - Version and npm package name.
34
+ * @returns {string} Pattern with placeholders replaced.
35
+ */
36
+ export declare function expandArtifactPattern(pattern: string, { version, packageName }: {
37
+ version: string;
38
+ packageName: string;
39
+ }): string;
40
+ /**
41
+ * Finds the newest file that matches an artifact pattern.
42
+ *
43
+ * @param {string} repositoryRoot - Repository root.
44
+ * @param {string} pattern - Configured pattern with `{version}` and optional `{name}`, `*` and `{sha256}`.
45
+ * @param {{ version: string, packageName: string }} release - Version and npm package name.
46
+ * @returns {PreparedArtifact | null} Path relative to the root with `/` separators and the digest its path declares, or `null`.
47
+ * Paths whose segments declare different digests never match.
48
+ */
49
+ export declare function findPreparedArtifact(repositoryRoot: string, pattern: string, release: {
50
+ version: string;
51
+ packageName: string;
52
+ }): PreparedArtifact | null;
53
+ /**
54
+ * Checks that an artifact path can be passed to `npm publish` on a shell command line.
55
+ *
56
+ * @param {string} artifactPath - Relative path found by {@link findPreparedArtifact}.
57
+ * @returns {boolean} Whether the path only uses safe characters.
58
+ */
59
+ export declare function isSafeArtifactPath(artifactPath: string): boolean;
60
+ /**
61
+ * Computes the SHA-256 of a file.
62
+ *
63
+ * @param {string} filePath - Absolute path.
64
+ * @returns {string} Lowercase hexadecimal digest.
65
+ */
66
+ export declare function computeSha256(filePath: string): string;
67
+ /**
68
+ * Computes the npm integrity of a file: the same `sha512-<base64>` string that
69
+ * `npm pack --json` reports for the archive it writes.
70
+ *
71
+ * @param {string} filePath - Absolute path.
72
+ * @returns {string} Subresource-integrity string.
73
+ */
74
+ export declare function computeNpmIntegrity(filePath: string): string;
75
+ /**
76
+ * Lists what a manifest needs from `pnpm pack` and npm would publish as it is: `workspace:`,
77
+ * `catalog:` or `jsr:` specifiers in published dependency maps, and `publishConfig` keys pnpm hoists onto the
78
+ * manifest (such as `exports`, `main` or `bin`; npm only reads `publishConfig` as configuration).
79
+ * Every other `publishConfig` key is npm configuration and is accepted.
80
+ *
81
+ * @param {PackageManifest} manifest - `package.json` of the release checkout.
82
+ * @returns {string[]} Problems in Spanish; empty when npm packs the package as pnpm would.
83
+ */
84
+ export declare function findPnpmPackRewrites(manifest: PackageManifest): string[];
85
+ /**
86
+ * Runs an operation with the prepared archive moved out of the package root, and always puts it
87
+ * back afterwards, also when the operation fails.
88
+ *
89
+ * `npm pack --dry-run` describes every file npm would pack now. When the package has no `files`
90
+ * allowlist and neither `.npmignore` nor `.gitignore` excludes the archive directory, the archive
91
+ * written by `prepare` (for example `releases/pkg-1.0.0.tgz`) would be packed into the package it
92
+ * is compared with, changing the integrity and rejecting a valid artifact. Hiding it reproduces the
93
+ * package root `prepare` packed: a directory left empty is ignored by npm, as it was then.
94
+ *
95
+ * @template T
96
+ * @param {string} repositoryRoot - Package root.
97
+ * @param {string} artifactPath - Archive relative to the root, found by {@link findPreparedArtifact}.
98
+ * @param {() => Promise<T>} operation - Runs while the archive is outside the package root.
99
+ * @param {string} [parentDirectory] - Where the holding directory is created; defaults to the OS temp directory.
100
+ * @returns {Promise<T>} The operation result.
101
+ */
102
+ export declare function withArtifactOutsidePackageRoot<T>(repositoryRoot: string, artifactPath: string, operation: () => Promise<T>, parentDirectory?: string): Promise<T>;
103
+ /**
104
+ * Verifies a prepared archive before publishing it: the SHA-256 its path declares (when the
105
+ * pattern uses `{sha256}`) and the SHA-512 integrity `npm pack --dry-run` reports for the release
106
+ * checkout, so the archive is byte for byte what npm packs from that commit.
107
+ *
108
+ * @param {string} repositoryRoot - Repository root.
109
+ * @param {PreparedArtifact} artifact - Archive found by {@link findPreparedArtifact}.
110
+ * @param {string} expectedIntegrity - `integrity` of `npm pack --dry-run --json --ignore-scripts`.
111
+ * @returns {string[]} Problems in Spanish; empty when the archive can be published.
112
+ */
113
+ export declare function verifyPreparedArtifact(repositoryRoot: string, artifact: PreparedArtifact, expectedIntegrity: string): string[];
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Isolated workspace where the changelog drafting agents run: a temporary directory outside the
3
+ * repository with a snapshot of the files Git tracks at `HEAD` and the release context (diff and
4
+ * log of the release range, plus the working tree changelog) that astra-rp reads for them. The
5
+ * agents never see the checkout, its `.git` directory nor its untracked files, and need no Git
6
+ * command of their own.
7
+ *
8
+ * @module create-version/changelog-draft-workspace
9
+ */
10
+ export type ChangelogDraftWorkspaceRequest = {
11
+ repositoryRoot: string;
12
+ lastReleaseSha: string | null;
13
+ changelogPath: string;
14
+ };
15
+ export type ChangelogDraftWorkspace = {
16
+ directory: string;
17
+ remove: () => void;
18
+ };
19
+ /**
20
+ * @typedef {{ repositoryRoot: string, lastReleaseSha: string | null, changelogPath: string }} ChangelogDraftWorkspaceRequest
21
+ * @typedef {{ directory: string, remove: () => void }} ChangelogDraftWorkspace
22
+ */
23
+ /**
24
+ * Creates the workspace: `repository/` with the tracked files at `HEAD`, and `release-context/`
25
+ * with the diff of the release range (without the changelog the agents are drafting), its
26
+ * `git log --stat` and the working tree changelog they will update, when it is a regular file.
27
+ * Without a previous release, the range is the whole history.
28
+ *
29
+ * @param {ChangelogDraftWorkspaceRequest} request - Repository, last release and changelog path.
30
+ * @returns {Promise<ChangelogDraftWorkspace>} Workspace directory and how to remove it.
31
+ * @throws {Error} When Git fails or the changelog cannot be copied; the partial workspace is removed and the original error is the `cause`.
32
+ */
33
+ export declare function createChangelogDraftWorkspace({ repositoryRoot, lastReleaseSha, changelogPath }: ChangelogDraftWorkspaceRequest): Promise<ChangelogDraftWorkspace>;
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Drafts the `[Unreleased]` entries of a changelog with an agent CLI when a new release would stop
3
+ * because they are missing. The agents are tried in the configured order (Claude Code, then Codex
4
+ * by default): each one reads an isolated, read-only copy of the repository with the release diff
5
+ * and log, outside the checkout, and answers the entries as Markdown,
6
+ * which astra-rp checks before writing them. The first valid answer wins; when every agent fails,
7
+ * the caller reports why and the release stops as it does without drafting.
8
+ *
9
+ * @module create-version/changelog-draft
10
+ */
11
+ export type ChangelogDraftProvider = "claude" | "codex";
12
+ export type AgentInvocation = {
13
+ command: string;
14
+ shell: boolean;
15
+ };
16
+ export type AgentAnswer = {
17
+ answer: string;
18
+ reason: null;
19
+ } | {
20
+ answer: null;
21
+ reason: string;
22
+ };
23
+ export type ParsedChangelogDraft = {
24
+ entries: string;
25
+ reason: null;
26
+ } | {
27
+ entries: null;
28
+ reason: string;
29
+ };
30
+ export type ChangelogDraftFailure = {
31
+ provider: ChangelogDraftProvider;
32
+ reason: string;
33
+ };
34
+ export type ChangelogDraftResult = {
35
+ provider: ChangelogDraftProvider;
36
+ entries: string;
37
+ failures: ChangelogDraftFailure[];
38
+ } | {
39
+ provider: null;
40
+ entries: null;
41
+ failures: ChangelogDraftFailure[];
42
+ };
43
+ export type ChangelogDraftRequest = {
44
+ packageName: string;
45
+ changelogPath: string;
46
+ lastReleaseSha: string | null;
47
+ commits: readonly {
48
+ sha?: string;
49
+ subject: string;
50
+ }[];
51
+ };
52
+ export type ChangelogDraftOptions = {
53
+ providers: readonly ChangelogDraftProvider[];
54
+ repositoryRoot: string;
55
+ request: ChangelogDraftRequest;
56
+ timeoutMs?: number;
57
+ onAttempt?: (provider: ChangelogDraftProvider) => void;
58
+ onFailure?: (failure: ChangelogDraftFailure) => void;
59
+ };
60
+ /**
61
+ * @typedef {"claude" | "codex"} ChangelogDraftProvider
62
+ * @typedef {{ command: string, shell: boolean }} AgentInvocation
63
+ * @typedef {{ answer: string, reason: null } | { answer: null, reason: string }} AgentAnswer
64
+ * @typedef {{ entries: string, reason: null } | { entries: null, reason: string }} ParsedChangelogDraft
65
+ * @typedef {{ provider: ChangelogDraftProvider, reason: string }} ChangelogDraftFailure
66
+ * @typedef {{ provider: ChangelogDraftProvider, entries: string, failures: ChangelogDraftFailure[] }
67
+ * | { provider: null, entries: null, failures: ChangelogDraftFailure[] }} ChangelogDraftResult
68
+ * @typedef {{
69
+ * packageName: string,
70
+ * changelogPath: string,
71
+ * lastReleaseSha: string | null,
72
+ * commits: readonly { sha?: string, subject: string }[],
73
+ * }} ChangelogDraftRequest
74
+ * @typedef {{
75
+ * providers: readonly ChangelogDraftProvider[],
76
+ * repositoryRoot: string,
77
+ * request: ChangelogDraftRequest,
78
+ * timeoutMs?: number,
79
+ * onAttempt?: (provider: ChangelogDraftProvider) => void,
80
+ * onFailure?: (failure: ChangelogDraftFailure) => void,
81
+ * }} ChangelogDraftOptions
82
+ */
83
+ /**
84
+ * Writes the prompt the agent receives: what to draft, the files of the isolated workspace it runs
85
+ * in (snapshot and release context) and the exact answer format astra-rp accepts. The project rules
86
+ * about the changelog win over these guidelines.
87
+ *
88
+ * @param {ChangelogDraftRequest} request - Package, changelog and commits of the release.
89
+ * @returns {string} Prompt in Spanish.
90
+ */
91
+ export declare function buildChangelogDraftPrompt({ packageName, changelogPath, lastReleaseSha, commits }: ChangelogDraftRequest): string;
92
+ /**
93
+ * Checks an agent answer before it reaches the terminal or the changelog: an answer with control
94
+ * characters (see {@link CONTROL_CHARACTER_PATTERN}) is rejected, an optional Markdown fence is
95
+ * removed, and the rest must be Keep a Changelog sections and nothing else, with the structure
96
+ * {@link findSectionStructureProblem} requires.
97
+ *
98
+ * @param {string} answer - Text the agent answered.
99
+ * @returns {ParsedChangelogDraft} Entries to write, or why the answer cannot be used.
100
+ */
101
+ export declare function parseChangelogDraft(answer: string): ParsedChangelogDraft;
102
+ /**
103
+ * Tries each agent CLI in order until one answers entries {@link parseChangelogDraft} accepts. The
104
+ * agents run in one isolated workspace (see {@link createChangelogDraftWorkspace}), removed at the
105
+ * end. An agent that is not installed, has no quota left, fails, takes longer than the limit or
106
+ * answers in another format counts as a failure, and the next one is tried; when the workspace
107
+ * cannot be created, every agent fails with that reason.
108
+ *
109
+ * @param {ChangelogDraftOptions} options - Agents in order, repository, release and progress callbacks.
110
+ * @returns {Promise<ChangelogDraftResult>} Entries and the agent that wrote them, or every failure.
111
+ */
112
+ export declare function draftChangelogEntries({ providers, repositoryRoot, request, timeoutMs, onAttempt, onFailure }: ChangelogDraftOptions): Promise<ChangelogDraftResult>;
113
+ /**
114
+ * Names an agent CLI for the terminal.
115
+ *
116
+ * @param {ChangelogDraftProvider} provider - Agent CLI.
117
+ * @returns {string} Label such as `Claude Code`.
118
+ */
119
+ export declare function describeChangelogDraftProvider(provider: ChangelogDraftProvider): string;
120
+ /**
121
+ * Finds how to start an agent CLI. Elsewhere `PATH` lookup happens on spawn; Windows needs `where`
122
+ * because npm installs CLIs as `.cmd` shims, which only a shell runs.
123
+ *
124
+ * @param {string} executable - Executable name.
125
+ * @returns {Promise<AgentInvocation | null>} Invocation, or `null` when the executable is not on `PATH`.
126
+ */
127
+ export declare function resolveAgentInvocation(executable: string): Promise<AgentInvocation | null>;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Verifies manually maintained changelogs and closes their `[Unreleased]` section in the release
3
+ * commit: the entries are written by hand (or drafted with `changelogDraft`), the version heading
4
+ * and its date by the release.
5
+ *
6
+ * @module create-version/changelog
7
+ */
8
+ export type ChangelogUpdateState = {
9
+ updated: boolean;
10
+ reason: string | null;
11
+ };
12
+ export type PreservedReleaseFile = {
13
+ filePath: string;
14
+ originalBytes: Buffer;
15
+ };
16
+ export type ChangelogContext = {
17
+ repositoryRoot: string;
18
+ reader: import("./process.js").GitReader;
19
+ commands: import("../package-manager.js").ProjectCommands;
20
+ };
21
+ export type UnreleasedEntriesState = {
22
+ exists: boolean;
23
+ entryCount: number;
24
+ };
25
+ /**
26
+ * @typedef {{ updated: boolean, reason: string | null }} ChangelogUpdateState
27
+ * @typedef {{ filePath: string, originalBytes: Buffer }} PreservedReleaseFile
28
+ * @typedef {{ repositoryRoot: string, reader: import("./process.js").GitReader, commands: import("../package-manager.js").ProjectCommands }} ChangelogContext
29
+ * @typedef {{ exists: boolean, entryCount: number }} UnreleasedEntriesState
30
+ */
31
+ /**
32
+ * Compares a changelog with its last release using Git's normalized blob hashes. Local edits,
33
+ * staged edits and committed edits all count; an initial release requires an existing file.
34
+ *
35
+ * @param {import("./process.js").GitReader} reader - Read-only Git adapter.
36
+ * @param {string} repositoryRoot - Repository root.
37
+ * @param {string} filePath - Changelog path relative to the repository root.
38
+ * @param {string | null} releaseRevision - Last release commit, or `null` for an initial release.
39
+ * @returns {Promise<ChangelogUpdateState>} Whether the file was updated, or why publication must stop.
40
+ */
41
+ export declare function readChangelogUpdateState(reader: import("./process.js").GitReader, repositoryRoot: string, filePath: string, releaseRevision: string | null): Promise<ChangelogUpdateState>;
42
+ /**
43
+ * Explains why a changelog cannot be closed in the release commit: it has no `## [Unreleased]`
44
+ * block, or that block has no entry (`- ` line) to release.
45
+ *
46
+ * @param {UnreleasedEntriesState} unreleased - `[Unreleased]` block of the changelog.
47
+ * @param {string} filePath - Changelog path relative to the repository root.
48
+ * @returns {string | null} Reason in Spanish, or `null` when the block has entries.
49
+ */
50
+ export declare function describeMissingUnreleasedEntries(unreleased: UnreleasedEntriesState, filePath: string): string | null;
51
+ /**
52
+ * Tells whether `[Unreleased]` holds nothing an agent draft would discard: only blank lines and
53
+ * `### <change type>` headings. Comments, release instructions or template text written there by
54
+ * the user (maybe not committed yet) keep the block from being drafted.
55
+ *
56
+ * @param {import("../changelog.js").UnreleasedState} unreleased - `[Unreleased]` block of the changelog.
57
+ * @returns {boolean} Whether drafted entries can replace the block body.
58
+ */
59
+ export declare function hasOnlyEmptySections(unreleased: import("../changelog.js").UnreleasedState): boolean;
60
+ /**
61
+ * Writes drafted entries as the body of `[Unreleased]`, replacing what the block held (an empty
62
+ * block, or empty section headings; see {@link hasOnlyEmptySections}). Creates the block, or the
63
+ * document, when missing, keeps the released history and uses the line breaks of a CRLF changelog.
64
+ *
65
+ * @param {string} changelog - Existing contents, or an empty string for a new file.
66
+ * @param {string} entries - `### Section` headings and `- ` entries, without the `## [Unreleased]` heading.
67
+ * @returns {string} Changelog whose `[Unreleased]` block holds `entries`.
68
+ */
69
+ export declare function fillUnreleasedEntries(changelog: string, entries: string): string;
70
+ /**
71
+ * Says how to fix a changelog the release cannot close, without touching the version.
72
+ *
73
+ * @param {string} filePath - Changelog path relative to the repository root.
74
+ * @param {string} createVersionCommand - Project command that runs `create-version`.
75
+ * @returns {string} Actionable hint in Spanish.
76
+ */
77
+ export declare function describeUnreleasedEntriesHint(filePath: string, createVersionCommand: string): string;
78
+ /**
79
+ * Requires a manual changelog update and captures its bytes, so the release can tell whether a
80
+ * later step changed them before closing `[Unreleased]`.
81
+ *
82
+ * @param {ChangelogContext} context - Release context.
83
+ * @param {string} filePath - Changelog path relative to the repository root.
84
+ * @param {string | null} releaseRevision - Last release commit, or `null` for an initial release.
85
+ * @returns {Promise<PreservedReleaseFile>} Changelog and its bytes before the release steps.
86
+ * @throws {ReleaseStepError} When the changelog is missing, unchanged or cannot be read.
87
+ */
88
+ export declare function verifyChangelogUpdate(context: ChangelogContext, filePath: string, releaseRevision: string | null): Promise<PreservedReleaseFile>;
89
+ /**
90
+ * Requires entries in the `[Unreleased]` block of a verified changelog, which the release commit closes.
91
+ *
92
+ * @param {ChangelogContext} context - Release context.
93
+ * @param {PreservedReleaseFile} changelog - Changelog captured by {@link verifyChangelogUpdate}.
94
+ * @returns {string} Changelog text, decoded as strict UTF-8.
95
+ * @throws {ReleaseStepError} When the changelog is not valid UTF-8, or `[Unreleased]` is missing or has no entries.
96
+ */
97
+ export declare function assertUnreleasedEntries(context: ChangelogContext, changelog: PreservedReleaseFile): string;
98
+ /**
99
+ * Stops when a check or hook changed a changelog after the release captured it: closing
100
+ * `[Unreleased]` over those bytes would ship content the release never verified.
101
+ *
102
+ * @param {ChangelogContext} context - Release context.
103
+ * @param {readonly PreservedReleaseFile[]} files - Files captured before running release steps.
104
+ * @returns {void}
105
+ * @throws {ReleaseStepError} When a file changed, disappeared or cannot be read.
106
+ */
107
+ export declare function assertPreservedFilesUnchanged(context: ChangelogContext, files: readonly PreservedReleaseFile[]): void;
108
+ /**
109
+ * Formats a date as the `YYYY-MM-DD` day Keep a Changelog gives a version: the day in `timeZone`
110
+ * when the project configures `releaseTimeZone`, so a release prepared on a CI runner in UTC keeps
111
+ * the team's day, or the machine's local day otherwise.
112
+ *
113
+ * @param {Date} [date] - Moment to format; the current time by default.
114
+ * @param {string | null} [timeZone] - IANA time zone already validated by the configuration, or `null` for the local day.
115
+ * @returns {string} Release day in `YYYY-MM-DD` format.
116
+ */
117
+ export declare function formatReleaseDate(date?: Date, timeZone?: string | null): string;
118
+ /**
119
+ * Closes the `[Unreleased]` section: its heading becomes `## [version] - releaseDate`, keeping its
120
+ * body, and a new empty `## [Unreleased]` goes on top. Every other byte is kept, including the
121
+ * line breaks of a CRLF changelog and section names outside Keep a Changelog.
122
+ *
123
+ * @param {string} changelog - Changelog contents.
124
+ * @param {string} version - Version being released.
125
+ * @param {string} releaseDate - Release day in `YYYY-MM-DD` format.
126
+ * @returns {string} Changelog with the section closed.
127
+ * @throws {Error} When the changelog has no `[Unreleased]` heading or that block has no entries.
128
+ */
129
+ export declare function closeUnreleasedSection(changelog: string, version: string, releaseDate: string): string;
130
+ /**
131
+ * Prepares the release-commit update of a verified changelog: checks that no step changed it since
132
+ * it was captured and closes its `[Unreleased]` section for `version`.
133
+ *
134
+ * @param {ChangelogContext} context - Release context.
135
+ * @param {PreservedReleaseFile} changelog - Changelog captured by {@link verifyChangelogUpdate}.
136
+ * @param {string} version - Version being released.
137
+ * @param {string} releaseDate - Release day in `YYYY-MM-DD` format.
138
+ * @returns {import("./run.js").ReleaseFileUpdate} File to write, with its bytes before the release.
139
+ * @throws {ReleaseStepError} When a step changed the changelog, it is not valid UTF-8 or `[Unreleased]` cannot be closed.
140
+ */
141
+ export declare function prepareChangelogClosing(context: ChangelogContext, changelog: PreservedReleaseFile, version: string, releaseDate: string): import("./run.js").ReleaseFileUpdate;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Validates repository-owned CI release settings.
3
+ * @module create-version/ci-config
4
+ */
5
+ export type CiReleaseConfig = {
6
+ workflow: string;
7
+ secrets?: string[];
8
+ variables?: string[];
9
+ deployment?: "vercel" | null;
10
+ };
11
+ export type ResolvedCiReleaseConfig = {
12
+ workflow: string;
13
+ secrets: string[];
14
+ variables: string[];
15
+ deployment: "vercel" | null;
16
+ };
17
+ /**
18
+ * @typedef {{ workflow: string, secrets?: string[], variables?: string[], deployment?: "vercel" | null }} CiReleaseConfig
19
+ * @typedef {{ workflow: string, secrets: string[], variables: string[], deployment: "vercel" | null }} ResolvedCiReleaseConfig
20
+ */
21
+ /**
22
+ * Builds the root-relative path of a workflow file.
23
+ * @param {string} workflow - Validated workflow filename.
24
+ * @returns {string} Path under {@link CI_WORKFLOW_DIRECTORY}.
25
+ */
26
+ export declare function ciWorkflowPath(workflow: string): string;
27
+ /**
28
+ * Resolves a workflow basename and explicit environment bindings.
29
+ * @param {unknown} raw - Repository-owned configuration, or null to disable CI releases.
30
+ * @returns {ResolvedCiReleaseConfig | null} Validated configuration.
31
+ * @throws {Error} When the workflow path or environment names are invalid.
32
+ */
33
+ export declare function resolveCiReleaseConfig(raw: unknown): ResolvedCiReleaseConfig | null;