code-foundry 1.33.2 → 1.34.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.
@@ -285,12 +285,12 @@ jobs:
285
285
  set -euo pipefail
286
286
  if [ "$WRANGLER_VERSION" = local ]; then
287
287
  if [ -n "$BUILD_SCRIPT" ]; then
288
- wrangler=(bunx --bun --no-install wrangler)
288
+ wrangler=(npx --no-install wrangler)
289
289
  else
290
290
  wrangler=(npx --no-install wrangler)
291
291
  fi
292
292
  elif [ -n "$BUILD_SCRIPT" ]; then
293
- wrangler=(bunx --bun "wrangler@$WRANGLER_VERSION")
293
+ wrangler=(npx -y "wrangler@$WRANGLER_VERSION")
294
294
  else
295
295
  wrangler=(npx -y "wrangler@$WRANGLER_VERSION")
296
296
  fi
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.34.0](https://github.com/0xPlayerOne/code-foundry/compare/v1.33.3...v1.34.0) (2026-09-29)
4
+
5
+
6
+ ### Features
7
+
8
+ * billing-paused-dependabot ([#651](https://github.com/0xPlayerOne/code-foundry/issues/651)) ([eda05b5](https://github.com/0xPlayerOne/code-foundry/commit/eda05b5cfa28fc7314ec33a94e539a1660549511))
9
+
10
+ ## [1.33.3](https://github.com/0xPlayerOne/code-foundry/compare/v1.33.2...v1.33.3) (2026-09-29)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **ci:** launch wrangler under Node in the cloudflare deploy step ([#649](https://github.com/0xPlayerOne/code-foundry/issues/649)) ([e797934](https://github.com/0xPlayerOne/code-foundry/commit/e7979343d3ff4d1fe5dc1520568a501cce0c47f3))
16
+
3
17
  ## [1.33.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.33.1...v1.33.2) (2026-09-26)
4
18
 
5
19
 
@@ -45,6 +45,7 @@ to require an existing mise configuration.
45
45
  | `runtime_ref` | tag or commit | Runtime version used by generated callers. |
46
46
  | `features` | `all` or a list | See [Feature selection](#feature-selection). |
47
47
  | `draft_protection` | `true`, `false` | Skip generated runner-heavy gates for draft PRs when false. |
48
+ | `billing_paused` | `true`, `false` | Disable Dependabot version updates while CI billing is paused. |
48
49
  | `codeql` | `auto`, `true`, `false` | Enable CodeQL when the repository and GitHub plan support it. |
49
50
  | `dependency_review` | `auto`, `true`, `false` | Enable Dependency Review when supported. |
50
51
  | `runner` and `*_runner` | GitHub runner labels | Override the default runner per workflow. |
@@ -62,6 +63,14 @@ intentionally runs generated gates for draft PRs. Cloudflare reusable-workflow
62
63
  callers use their equivalent `draft-protection` input. These opt-outs affect
63
64
  CI/deployment gates only and do not disable Draft Guard or draft-PR automation.
64
65
 
66
+ The `CI_BILLING_PAUSED` repository variable gates every generated workflow job,
67
+ but Dependabot's update runs execute under the `dynamic` event and never see
68
+ that variable. Set `billing_paused: true` alongside the variable and re-run
69
+ `sync` so the rendered `dependabot.yml` sets `open-pull-requests-limit: 0` and
70
+ drops the update cadence to monthly for every ecosystem. Removing the flag and
71
+ syncing again restores the active template. `npx code-foundry ci status` reports
72
+ when a paused repository still has Dependabot updates active.
73
+
65
74
  ## Feature selection
66
75
 
67
76
  Use `features: all` or a comma/space-separated list. The canonical validation
package/docs/WORKFLOWS.md CHANGED
@@ -128,6 +128,14 @@ second toggle: the `OPENCODE_SECURITY` repository or organization variable
128
128
  (`true`/`false`) is its only enablement control, so individual repositories can
129
129
  opt in or out without a code change.
130
130
 
131
+ Dependabot is the one billable runner source the variable cannot gate: its
132
+ update runs execute under the `dynamic` event, outside every job-level guard.
133
+ While paused, set `billing_paused: true` in `.github/code-foundry.yml` and run a
134
+ sync so the rendered `dependabot.yml` disables version updates
135
+ (`open-pull-requests-limit: 0`, monthly cadence). Remove the flag and sync to
136
+ restore updates when billing resumes. `npx code-foundry ci status` reports the
137
+ Dependabot state, and `pause` warns when updates are still active.
138
+
131
139
  ## Standard workflow responsibilities
132
140
 
133
141
  | Workflow | Responsibility |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "code-foundry",
3
- "version": "1.33.2",
3
+ "version": "1.34.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": {
@@ -1,6 +1,8 @@
1
1
  // @ts-check
2
2
 
3
3
  import { spawnSync } from 'node:child_process'
4
+ import { existsSync, readFileSync } from 'node:fs'
5
+ import { readConfig } from '../lib/config.mjs'
4
6
 
5
7
  export const CI_BILLING_PAUSED_VARIABLE = 'CI_BILLING_PAUSED'
6
8
  export const CI_BILLING_BACKUP_VARIABLE = 'CI_BILLING_GATE_BACKUP'
@@ -26,11 +28,13 @@ export function manageCiBilling(root, action) {
26
28
  const backup = backupText ? parseBackup(backupText) : null
27
29
 
28
30
  if (action === 'status') {
31
+ const dependabot = dependabotPauseState(root)
29
32
  const result = {
30
33
  repository,
31
34
  paused,
32
35
  requiredCheck: CI_BILLING_REQUIRED_CHECK,
33
36
  backupPresent: Boolean(backup),
37
+ dependabot,
34
38
  }
35
39
  console.log(JSON.stringify(result, null, 2))
36
40
  return result
@@ -87,12 +91,25 @@ export function manageCiBilling(root, action) {
87
91
  setVariable(repository, CI_BILLING_PAUSED_VARIABLE, 'true')
88
92
  const cancelledRuns = cancelActiveRuns(repository)
89
93
  for (const change of changes) updateRuleset(repository, change.ruleset)
94
+ const dependabot = dependabotPauseState(root)
90
95
  const result = {
91
96
  repository,
92
97
  paused: true,
93
98
  changed: true,
94
99
  cancelledRuns,
95
100
  rulesets: changes.map((change) => change.ruleset.name),
101
+ // Dependabot update runs execute under the `dynamic` event, so the
102
+ // repository variable alone never stops them. Surface the gap every
103
+ // time so a paused repository cannot keep burning minutes silently.
104
+ dependabot,
105
+ ...(dependabot.active
106
+ ? {
107
+ dependabotWarning:
108
+ 'Dependabot version updates are still active and are not gated by ' +
109
+ `${CI_BILLING_PAUSED_VARIABLE}. Set billing_paused: true in .github/code-foundry.yml ` +
110
+ 'and run a sync so dependabot.yml renders open-pull-requests-limit: 0.',
111
+ }
112
+ : {}),
96
113
  }
97
114
  console.log(JSON.stringify(result, null, 2))
98
115
  return result
@@ -133,6 +150,31 @@ export function manageCiBilling(root, action) {
133
150
  return result
134
151
  }
135
152
 
153
+ /**
154
+ * Inspect whether Dependabot version updates are still active in the working
155
+ * tree. The repository variable gates workflow jobs but not Dependabot's own
156
+ * `dynamic` update runs, so a paused repository also needs dependabot.yml to
157
+ * render `open-pull-requests-limit: 0` (the `billing_paused` config does this
158
+ * during sync). An ecosystem without an explicit limit of 0 counts as active
159
+ * because Dependabot defaults the limit to 5.
160
+ *
161
+ * @param {string} root
162
+ * @returns {{ configured: boolean, active: boolean, file: string }}
163
+ */
164
+ export function dependabotPauseState(root) {
165
+ const file = '.github/dependabot.yml'
166
+ const path = `${root.replace(/\/$/, '')}/${file}`
167
+ if (!existsSync(path)) return { configured: false, active: false, file }
168
+ const source = readFileSync(path, 'utf8')
169
+ const configured =
170
+ readConfig(`${root.replace(/\/$/, '')}/.github/code-foundry.yml`).billing_paused === 'true'
171
+ const blocks = source
172
+ .split(/(?=^ - package-ecosystem: )/m)
173
+ .filter((block) => block.startsWith(' - package-ecosystem: '))
174
+ const active = blocks.some((block) => !/^ open-pull-requests-limit: 0(\s|#|$)/m.test(block))
175
+ return { configured, active, file }
176
+ }
177
+
136
178
  /** @param {any} ruleset */
137
179
  export function buildPausedRuleset(ruleset) {
138
180
  const requiredRuleIndexes = (ruleset.rules ?? []).flatMap(
@@ -823,12 +823,21 @@ function removeWorkflowBlock(content, blockId) {
823
823
  * part of the configured language set, respectively; weekly updater runs
824
824
  * fail when an ecosystem has no manifests to read, so unconfigured
825
825
  * ecosystems are dropped instead of left to error.
826
+ *
827
+ * The billing pause must also cover Dependabot: its update runs execute as
828
+ * Actions workflows under the `dynamic` event, so the `CI_BILLING_PAUSED`
829
+ * repository variable that gates every workflow job cannot stop them. When
830
+ * `billing_paused: true` is configured, version updates are disabled by
831
+ * rendering `open-pull-requests-limit: 0` and dropping the cadence to
832
+ * monthly; `schedule` is a required key, so the ecosystem blocks stay
833
+ * structurally valid and a later sync with the flag removed restores the
834
+ * template verbatim.
826
835
  * @param {string} content
827
836
  * @param {Record<string,string>} config
828
837
  * @param {string} languages
829
838
  * @returns {string}
830
839
  */
831
- function renderDependabot(content, config, languages) {
840
+ export function renderDependabot(content, config, languages) {
832
841
  let rendered = content
833
842
  if (!includesValue(languages, 'rust')) {
834
843
  rendered = stripDependabotEcosystem(rendered, 'cargo')
@@ -839,10 +848,33 @@ function renderDependabot(content, config, languages) {
839
848
  if (!includesValue(languages, 'python')) {
840
849
  rendered = stripDependabotEcosystem(rendered, 'pip')
841
850
  }
851
+ if (configured(config.billing_paused, 'false') === 'true') {
852
+ rendered = pauseDependabot(rendered)
853
+ }
842
854
  if (isStagingRelease(config.git_workflow)) return rendered
843
855
  return rendered.replaceAll('target-branch: staging', 'target-branch: main')
844
856
  }
845
857
 
858
+ /**
859
+ * Disable Dependabot version updates for every remaining ecosystem. The
860
+ * transformations are regex-based so they hold for any ecosystem count and
861
+ * any future template default; an unchanged file after both replacements
862
+ * means the template stopped defining schedules or limits, which is a loud
863
+ * template drift the next sync test will catch.
864
+ * @param {string} content
865
+ * @returns {string}
866
+ */
867
+ function pauseDependabot(content) {
868
+ const limited = content.replace(
869
+ /^(\s*)open-pull-requests-limit:\s*\d+\s*$/gm,
870
+ `$1open-pull-requests-limit: 0 # billing_paused: version updates disabled`
871
+ )
872
+ return limited.replace(
873
+ /^(\s*)interval:\s*weekly\s*$/gm,
874
+ `$1interval: monthly # billing_paused: reduced cadence`
875
+ )
876
+ }
877
+
846
878
  /**
847
879
  * Remove one package-ecosystem update block from a dependabot template.
848
880
  * Blocks are split on their leading list marker so removal never disturbs