code-foundry 1.50.0 → 1.51.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.
@@ -13,6 +13,14 @@
13
13
  "type": "string",
14
14
  "enum": ["true", "false"]
15
15
  },
16
+ "release_defer_publication": {
17
+ "type": "string",
18
+ "enum": ["true", "false"]
19
+ },
20
+ "release_prerelease": {
21
+ "type": "string",
22
+ "enum": ["true", "false"]
23
+ },
16
24
  "npm_publish_auth": {
17
25
  "description": "npm publisher authentication: auto preserves token users and uses OIDC when no publish token is present; oidc forces trusted publishing; token requires NPM_TOKEN.",
18
26
  "type": "string",
@@ -90,7 +90,6 @@ jobs:
90
90
  contents: write
91
91
  issues: write
92
92
  pull-requests: write
93
- # Required by the reusable legacy workflow's declared npm job, which is disabled here.
94
93
  id-token: write
95
94
  secrets:
96
95
  CODE_FOUNDRY_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN }}
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.51.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.50.1...v1.51.0) (2026-10-29)
4
+
5
+
6
+ ### Features
7
+
8
+ * **release:** preserve caller publication overrides ([#795](https://github.com/0xPlayerOne/code-foundry/issues/795)) ([e49d2ba](https://github.com/0xPlayerOne/code-foundry/commit/e49d2bac4f8995808bfc6a726b0c2ff1e93c2a5f))
9
+
10
+ ## [1.50.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.50.0...v1.50.1) (2026-10-29)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **sync:** replace complete consumer runtime ref ([#793](https://github.com/0xPlayerOne/code-foundry/issues/793)) ([6a0b5ef](https://github.com/0xPlayerOne/code-foundry/commit/6a0b5ef4f9a02c781745fa64f2f9748ea679f2d5))
16
+
3
17
  ## [1.50.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.49.3...v1.50.0) (2026-10-29)
4
18
 
5
19
 
@@ -126,23 +140,9 @@
126
140
 
127
141
  * **fleet:** point the manifest at the rollout worktrees and filter adea's actionlint ([#757](https://github.com/0xPlayerOne/code-foundry/issues/757)) ([55bae8b](https://github.com/0xPlayerOne/code-foundry/commit/55bae8bf99a022bfa03294972d89a3cca20a6203))
128
142
 
129
- ## [1.47.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.47.1...v1.47.2) (2026-10-08)
130
-
131
-
132
- ### Bug Fixes
133
-
134
- * **qualification:** exclude pending parallel syntax by content, not filename ([#755](https://github.com/0xPlayerOne/code-foundry/issues/755)) ([1f7cae8](https://github.com/0xPlayerOne/code-foundry/commit/1f7cae8167002061850e56e3dc0fa800a69d7be9))
135
-
136
- ## [1.47.1](https://github.com/0xPlayerOne/code-foundry/compare/v1.47.0...v1.47.1) (2026-10-08)
137
-
138
-
139
- ### Tests
140
-
141
- * **doctor:** pin the machine-hook shadow warning ([#753](https://github.com/0xPlayerOne/code-foundry/issues/753)) ([f634269](https://github.com/0xPlayerOne/code-foundry/commit/f634269424580d8d34323319288747587b6d6ae3))
142
-
143
143
  <!-- code-foundry: packaged changelog -->
144
144
 
145
145
  ---
146
146
 
147
- This packaged changelog lists the 20 most recent releases; 262 older releases are omitted to keep the package small.
147
+ This packaged changelog lists the 20 most recent releases; 264 older releases are omitted to keep the package small.
148
148
  See the [full changelog](https://github.com/0xPlayerOne/code-foundry/blob/main/CHANGELOG.md) for the complete history.
@@ -178,6 +178,8 @@ See [Merge queue validation](merge-queues.md) before enabling it.
178
178
  | `release_qualification_receipts` | `true`, `false` (default `false`) | Opt in to seven-day source qualification receipts for eligible version-only Release Please PRs. Defaults to false; see [workflow policy](WORKFLOWS.md#standard-triggers) for requirements and fallback behavior. |
179
179
  | `release_batching_schedule` | five-field numeric cron | Batch Release Please into scheduled windows. Ordinary pushes skip the producer; release-PR squashes and manual dispatches still run. Batched releases are created privately as drafts and published with prerelease visibility atomically. Manual dispatches publish stable hotfixes. Absent, releases publish per merge. Requires a single root Release Please package. |
180
180
  | `release_batching_prerelease` | `true`, `false` | Defaults to `true` with a schedule. Sync enables `draft` and `force-tag-creation` in Release Please; the producer publishes the draft with the selected visibility. `false` keeps scheduled releases stable-visible. |
181
+ | `release_defer_publication` | `true`, `false` (default `false`) | Keep deferred publication enabled in the caller; the reusable workflow skips npm, reconciliation, and post-release hooks. Requires one draft root package with force-tag creation, configured directly or by prerelease batching. |
182
+ | `release_prerelease` | `true`, `false` (unset by default) | Set a fixed prerelease input; unset keeps event-based batching. |
181
183
  | `release_batching_soak_hours` | `1`–`336` | Generate a daily promoter that promotes the newest prerelease when the oldest candidate since the last stable has soaked this many hours, stitching batch notes. Requires a batching schedule and prerelease publication. Set `STABLE_PROMOTION_HELD=true` in repository Actions variables to hold scheduled and manual promotion; `force` overrides the hold or soak, and `version` selects a plain semantic version. |
182
184
  | `release_batching_qualification_workflow` | workflow filename (for example `release-assets.yml`) | Require the latest release-event run of this workflow for the candidate tag’s exact source commit to succeed before stable promotion. Requires a batching soak. Running, missing, failed, or cancelled runs hold promotion, including named and forced promotions; `force` only bypasses hold and soak. The promoter receives read-only Actions access. |
183
185
  | `release_batching_dev_channel` | `true`, `false` | Publish a dev channel: every push to main tags a `v<stable>-dev.<run>` pre-release on top of the newest stable and dispatches the configured asset lane. Dev builds are never promoted to stable, auto builds pause with `CI_BILLING_PAUSED`, and manual dispatches accept a `version` input for repairs. Defaults to `false`. |
@@ -14,8 +14,8 @@ budget is exceeded. Reports are generated-run evidence and are ignored by Git.
14
14
  | Format, lint, type-check, and build | 15 s | Bound the local CI feedback loop |
15
15
  | Runtime dependencies | 0 | Keep the installed CLI dependency-free |
16
16
  | Development dependencies | 4 | Prevent unreviewed toolchain growth |
17
- | Packed artifact (without changelog) | 296 kB | Bound registry transfer and install cost |
18
- | Unpacked artifact (without changelog) | 1,136 kB | Bound installed footprint |
17
+ | Packed artifact (without changelog) | 316.5 kB | Bound registry transfer and install cost |
18
+ | Unpacked artifact (without changelog) | 1,225 kB | Bound installed footprint |
19
19
  | Packed files (without changelog) | 120 | Detect accidental release contents |
20
20
 
21
21
  The source-of-truth budgets live in `scripts/performance-check.mjs`. When those
@@ -29,8 +29,14 @@ included it eroded on every release and repeatedly failed release pull requests.
29
29
  The check packs a staging copy without the changelog and reports the repository
30
30
  changelog size and its packaged (trimmed) size as informational metrics. At
31
31
  v1.44.0 the measured artifact was 280,902 packed bytes, 1,070,333 unpacked bytes,
32
- and 118 files, leaving roughly 5% packed and 6% unpacked headroom for source
33
- growth.
32
+ and 118 files.
33
+
34
+ On v1.50.1 base `f671dd8`, the measured artifact was 315,853 packed bytes,
35
+ 1,200,759 unpacked bytes, and 120 files. Release caller publication overrides
36
+ measure 316,295 packed bytes, 1,222,905 unpacked bytes, and 120 files: an
37
+ increase of 442 packed bytes and 22,146 unpacked bytes. The packed limit is
38
+ 316,500 bytes, leaving 205 bytes of measured headroom; the unpacked and file-count
39
+ limits remain 1,225,000 bytes and 120 files.
34
40
 
35
41
  The published package ships a changelog trimmed to the 20 most recent releases
36
42
  with a link to the full history on GitHub. `scripts/package-changelog.mjs`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.50.0",
3
+ "version": "1.51.0",
4
4
  "description": "A fast, language-aware repository factory for agent-ready workflows, testing, security, and release automation.",
5
5
  "homepage": "https://github.com/0xPlayerOne/code-foundry#readme",
6
6
  "bugs": {
@@ -900,6 +900,11 @@ jobs:
900
900
 
901
901
  /** @param {Record<string, string>} config */
902
902
  function validateReleaseBatchingConfig(config) {
903
+ for (const key of ['release_defer_publication', 'release_prerelease']) {
904
+ if (config[key] !== undefined && !['true', 'false'].includes(config[key])) {
905
+ throw new Error(`Unsupported ${key}: ${config[key]}; use true or false.`)
906
+ }
907
+ }
903
908
  const schedule = String(config.release_batching_schedule ?? '').trim()
904
909
  if (schedule) {
905
910
  const limits = [
@@ -1094,6 +1099,26 @@ export function renderDevChannel(config) {
1094
1099
  )
1095
1100
  }
1096
1101
 
1102
+ /**
1103
+ * Pin consumer runtime refs without retaining the self-CI expression used by
1104
+ * the Code Foundry repository. Self callers keep their event-relative refs.
1105
+ *
1106
+ * @param {string} content
1107
+ * @param {string} ref
1108
+ * @param {boolean} selfRepository
1109
+ */
1110
+ export function pinRuntimeRefs(content, ref, selfRepository) {
1111
+ if (selfRepository) return content
1112
+ const foldedRuntimeRef =
1113
+ /^([ \t]*runtime-ref:)[ \t]*>-[ \t]*\r?\n(?:[ \t]+\$\{\{[^\r\n]*\}\}[ \t]*(?:\r?\n|$))+/gm
1114
+ return content
1115
+ .replace(
1116
+ foldedRuntimeRef,
1117
+ (match, key) => `${key} ${ref}${match.endsWith('\r\n') ? '\r\n' : '\n'}`
1118
+ )
1119
+ .replace(/^([ \t]*runtime-ref:)[ \t]+.*$/gm, (_, key) => `${key} ${ref}`)
1120
+ }
1121
+
1097
1122
  /**
1098
1123
  * @param {string} content
1099
1124
  * @param {Record<string,string>} config
@@ -1149,11 +1174,12 @@ function renderWorkflow(content, config, repository, ref, rustCodeql, file, self
1149
1174
  new RegExp(`${escapeRegExp(remotePrefix)}([^\\s@]+)`, 'g'),
1150
1175
  `$&@${ref}`
1151
1176
  )
1152
- // Pin every runtime reference in the rendered caller: the orchestrator input
1153
- // in the `with:` block and the mode job's runtime checkout. Self templates
1154
- // use ${{ github.sha }} and are only rewritten when rendered for consumers.
1155
- rendered = rendered.replace(/^(\s+runtime-ref:)\s+.*$/gm, `$1 ${ref}`)
1156
- rendered = rendered.replace(/^(\s+ref:)\s+\$\{\{\s*github\.sha\s*\}\}\s*$/gm, `$1 ${ref}`)
1177
+ // Replace complete folded self-CI runtime expressions when rendering a
1178
+ // consumer. The source repository keeps its event-relative runtime refs.
1179
+ rendered = pinRuntimeRefs(rendered, ref, selfRepository)
1180
+ if (!selfRepository) {
1181
+ rendered = rendered.replace(/^(\s+ref:)\s+\$\{\{\s*github\.sha\s*\}\}\s*$/gm, `$1 ${ref}`)
1182
+ }
1157
1183
  rendered = rendered.replace(/^(\s+runtime-repository:)\s+.*$/gm, `$1 ${repository}`)
1158
1184
  rendered = rendered.replace(
1159
1185
  new RegExp(`^(\\s+repository:)\\s+0xPlayerOne\\/code-foundry\\s*$`, 'gm'),
@@ -1225,7 +1251,9 @@ function renderWorkflow(content, config, repository, ref, rustCodeql, file, self
1225
1251
  rendered = removeWorkflowBlock(rendered, job)
1226
1252
  rendered = rendered.replace(/^ needs: \[preflight\]\n/m, '')
1227
1253
  rendered = rendered.replace(/^ config-file: \.github\/release-please-foundry\.json\n/m, '')
1228
- rendered = rendered.replace(/^ defer-publication: true\n/m, '')
1254
+ if (config.release_defer_publication !== 'true') {
1255
+ rendered = rendered.replace(/^ defer-publication: true\n/m, '')
1256
+ }
1229
1257
  rendered = rendered.replace(
1230
1258
  /^ if: github\.ref == 'refs\/heads\/main' && \(vars\.CI_BILLING_PAUSED != 'true' \|\| \(github\.event_name == 'workflow_dispatch' && inputs\['release-while-paused'\] == true\)\)\n/m,
1231
1259
  " if: vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true)\n"
@@ -1245,12 +1273,17 @@ function renderWorkflow(content, config, repository, ref, rustCodeql, file, self
1245
1273
  " if: vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true)\n",
1246
1274
  " if: >-\n (vars.CI_BILLING_PAUSED != 'true' || (github.event_name == 'workflow_dispatch' && inputs['release-while-paused'] == true)) && (github.event_name != 'push' || startsWith(github.event.head_commit.message, 'chore(main): release '))\n"
1247
1275
  )
1248
- if (configured(config.release_batching_prerelease, 'true') === 'true') {
1249
- rendered = rendered.replace(
1250
- ' git-workflow:',
1251
- " prerelease: ${{ github.event_name != 'workflow_dispatch' }}\n git-workflow:"
1252
- )
1253
- }
1276
+ }
1277
+ const prerelease =
1278
+ config.release_prerelease ||
1279
+ (batchingSchedule && config.release_batching_prerelease !== 'false'
1280
+ ? "${{ github.event_name != 'workflow_dispatch' }}"
1281
+ : '')
1282
+ if (prerelease) {
1283
+ rendered = rendered.replace(
1284
+ ' git-workflow:',
1285
+ ` prerelease: ${prerelease}\n git-workflow:`
1286
+ )
1254
1287
  }
1255
1288
  const npmSecrets =
1256
1289
  configured(config.npm_publish, 'false') !== 'true'