code-foundry 0.26.0 → 0.27.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 (44) hide show
  1. package/.githooks/pre-commit +3 -4
  2. package/.github/CONTRIBUTING.md +10 -13
  3. package/.github/actions/setup/action.yml +68 -3
  4. package/.github/code-foundry.yml +6 -1
  5. package/.github/workflows/ci.yml +29 -24
  6. package/.github/workflows/ci_self-ci.yml +1 -1
  7. package/.github/workflows/codeql.yml +23 -29
  8. package/.github/workflows/codeql_self-ci.yml +1 -1
  9. package/.github/workflows/draft-pr.yml +2 -2
  10. package/.github/workflows/release-pr.yml +4 -4
  11. package/.github/workflows/release.yml +17 -29
  12. package/.github/workflows/security.yml +24 -19
  13. package/.github/workflows/security_self-ci.yml +1 -1
  14. package/.github/workflows/test.yml +20 -20
  15. package/.github/workflows/test_self-ci.yml +1 -1
  16. package/AGENTS.md +13 -10
  17. package/CHANGELOG.md +29 -0
  18. package/README.md +16 -6
  19. package/docs/CONFIGURATION.md +10 -1
  20. package/docs/INITIALIZATION.md +6 -5
  21. package/docs/RELEASES.md +5 -0
  22. package/docs/WORKFLOWS.md +12 -5
  23. package/package.json +7 -3
  24. package/src/cli.mjs +29 -25
  25. package/src/commands/doctor.mjs +70 -0
  26. package/src/commands/sync.mjs +224 -0
  27. package/src/lib/config.mjs +38 -0
  28. package/src/lib/profile.mjs +114 -0
  29. package/src/runtime.mjs +321 -0
  30. package/.github/scripts/bootstrap.sh +0 -21
  31. package/.github/scripts/changed-files.sh +0 -96
  32. package/.github/scripts/ci.sh +0 -641
  33. package/.github/scripts/codeql-languages.sh +0 -91
  34. package/.github/scripts/doctor.sh +0 -98
  35. package/.github/scripts/format-fast-path.sh +0 -80
  36. package/.github/scripts/init-repo.sh +0 -268
  37. package/.github/scripts/pre-commit.sh +0 -67
  38. package/.github/scripts/profile.sh +0 -186
  39. package/.github/scripts/security.sh +0 -214
  40. package/.github/scripts/sitecustomize.py +0 -17
  41. package/.github/scripts/sync-codeowners.sh +0 -76
  42. package/.github/scripts/sync-protection.sh +0 -138
  43. package/.github/scripts/sync-template.sh +0 -748
  44. package/.github/scripts/turbo-cache-probe.sh +0 -102
@@ -1,5 +1,4 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
1
+ #!/usr/bin/env sh
2
+ set -eu
3
3
 
4
- repo_root="$(git rev-parse --show-toplevel)"
5
- exec bash "$repo_root/.github/scripts/pre-commit.sh" "$@"
4
+ git diff --cached --check
@@ -48,14 +48,14 @@ docs/* test/* refactor/* │ │
48
48
  | `staging` | Integration branch | Target normal pull requests here. Required checks must pass before merge. |
49
49
  | `feat/*`, `fix/*`, `chore/*`, `refactor/*`, `docs/*`, `test/*` | Focused work | Branch from `staging`; keep changes small and reviewable. |
50
50
 
51
- Use squash merges unless the repository documents another strategy. Re-align `staging` with `main` after a release when needed.
51
+ The default Git workflow is `staging-release`: topic branches merge into `staging`, then a promotion PR moves validated changes into `main`, followed by the versioned release PR. The default merge strategy is `rebase`, which preserves the linear Conventional Commit history. Configure `merge_strategy` as `squash` or `merge` in `.github/code-foundry.yml` when the repository intentionally uses another policy. Re-align `staging` with `main` after a release when needed.
52
52
 
53
53
  ## Before you start
54
54
 
55
55
  ### Toolchain
56
56
 
57
- 1. Install [mise](https://mise.jdx.dev/).
58
- 2. Run `npx code-foundry init` to install the pinned toolchain, enable hooks, and validate the checkout.
57
+ 1. Run `npx code-foundry init` to detect the repository and enable hooks.
58
+ 2. Follow `toolchain: auto` in `.github/code-foundry.yml`; install mise only if the repository already uses it or explicitly selects it.
59
59
  3. Use `npx code-foundry doctor` when setup, lockfiles, or hooks appear out of sync.
60
60
  4. Use the repository's existing package manager and lockfile. Do not introduce a second package manager.
61
61
  5. Copy `.env.example` to the appropriate local environment file when provided. Never commit the copy.
@@ -74,17 +74,14 @@ If the worktree is dirty, stop and understand the existing changes before switch
74
74
 
75
75
  ## Local validation
76
76
 
77
- The template scripts detect supported tools and skip checks that do not apply:
77
+ The repository runtime detects supported tools and skips checks that do not apply:
78
78
 
79
79
  ```sh
80
- bash .github/scripts/ci.sh format
81
- bash .github/scripts/ci.sh lint
82
- bash .github/scripts/ci.sh type_check
83
- bash .github/scripts/ci.sh build
84
- bash .github/scripts/ci.sh unit
85
- bash .github/scripts/ci.sh integration
86
- bash .github/scripts/ci.sh e2e
87
- bash .github/scripts/ci.sh smoke
80
+ npx code-foundry doctor
81
+ npm run format:check # or the package manager's equivalent
82
+ npm run lint
83
+ npm run type-check
84
+ npm test
88
85
  Security and dependency audits run through the GitHub Security workflow.
89
86
  ```
90
87
 
@@ -110,7 +107,7 @@ For maintainers, trusted contributors, and automation agents:
110
107
 
111
108
  8. Push the branch and open a pull request into `staging`.
112
109
  9. Address review feedback and failed checks on the same branch.
113
- 10. Squash-merge only after required checks pass and the change is ready.
110
+ 10. Merge using the repository's configured `merge_strategy` after required checks pass and the change is ready.
114
111
 
115
112
  ### Internal agent handoff
116
113
 
@@ -1,5 +1,5 @@
1
1
  name: Repository Setup
2
- description: Install the pinned mise toolchain and optionally project dependencies.
2
+ description: Select mise or native language tooling and optionally install project dependencies.
3
3
 
4
4
  inputs:
5
5
  install:
@@ -85,6 +85,16 @@ runs:
85
85
  run: |
86
86
  tracked_files="$(git ls-files)"
87
87
 
88
+ toolchain="auto"
89
+ if [ -f .github/code-foundry.yml ]; then
90
+ configured_toolchain="$(awk -F': ' '/^toolchain:/ {print $2; exit}' .github/code-foundry.yml)"
91
+ [ -n "$configured_toolchain" ] && toolchain="$configured_toolchain"
92
+ fi
93
+ if [ "$toolchain" = auto ] && [ -f .mise.toml ]; then
94
+ toolchain=mise
95
+ fi
96
+ printf 'toolchain_mode=%s\n' "$toolchain" >> "$GITHUB_OUTPUT"
97
+
88
98
  has_tracked_regex() {
89
99
  printf '%s\n' "$tracked_files" | grep -Eq "$1"
90
100
  }
@@ -428,6 +438,61 @@ runs:
428
438
  REPO_FOUNDRY_TASK_RUST: ${{ inputs.task-rust }}
429
439
  REPO_FOUNDRY_CACHE_PACKAGES: ${{ inputs.cache-packages }}
430
440
 
441
+ - name: Install native test libraries
442
+ if: >-
443
+ inputs.install == 'true' &&
444
+ inputs.task == 'unit' &&
445
+ hashFiles('**/package.json') != '' &&
446
+ steps.profile.outputs.javascript == 'true'
447
+ shell: bash
448
+ run: |
449
+ if node -e '
450
+ const fs = require("node:fs");
451
+ const p = JSON.parse(fs.readFileSync("package.json", "utf8"));
452
+ const all = { ...p.dependencies, ...p.devDependencies, ...p.optionalDependencies };
453
+ process.exit(all["matchstick-as"] ? 0 : 1);
454
+ ' 2>/dev/null; then
455
+ sudo apt-get update -qq
456
+ sudo apt-get install -y -qq libpq5
457
+ fi
458
+
459
+ - name: Setup Node
460
+ if: >-
461
+ steps.profile.outputs.toolchain_mode != 'mise' &&
462
+ steps.profile.outputs.javascript == 'true' &&
463
+ steps.profile.outputs.javascript_package_manager != 'bun'
464
+ uses: actions/setup-node@v5
465
+ with:
466
+ node-version: 24
467
+ cache: ${{ steps.profile.outputs.javascript_package_manager == 'npm' && 'npm' || steps.profile.outputs.javascript_package_manager == 'pnpm' && 'pnpm' || steps.profile.outputs.javascript_package_manager == 'yarn' && 'yarn' || '' }}
468
+
469
+ - name: Setup Bun
470
+ if: >-
471
+ steps.profile.outputs.toolchain_mode != 'mise' &&
472
+ steps.profile.outputs.javascript == 'true' &&
473
+ steps.profile.outputs.javascript_package_manager == 'bun'
474
+ uses: oven-sh/setup-bun@v2
475
+ with:
476
+ bun-version: 1.3.14
477
+
478
+ - name: Enable Corepack
479
+ if: >-
480
+ steps.profile.outputs.toolchain_mode != 'mise' &&
481
+ (steps.profile.outputs.javascript_package_manager == 'pnpm' ||
482
+ steps.profile.outputs.javascript_package_manager == 'yarn')
483
+ shell: bash
484
+ run: corepack enable
485
+
486
+ - name: Setup Python
487
+ if: steps.profile.outputs.toolchain_mode != 'mise' && steps.profile.outputs.python == 'true'
488
+ uses: actions/setup-python@v6
489
+ with:
490
+ python-version: '3.13'
491
+
492
+ - name: Setup Rust
493
+ if: steps.profile.outputs.toolchain_mode != 'mise' && steps.profile.outputs.rust == 'true'
494
+ uses: dtolnay/rust-toolchain@stable
495
+
431
496
  - name: Setup uv
432
497
  if: >-
433
498
  steps.profile.outputs.python == 'true' &&
@@ -658,7 +723,7 @@ runs:
658
723
  path: ~/.cargo/advisory-db
659
724
  # The advisory database is independent of project dependencies. Keep
660
725
  # it warm for Security without invalidating it on every lockfile edit.
661
- key: ${{ runner.os }}-rust-advisory-${{ hashFiles('.github/scripts/security.sh') }}
726
+ key: ${{ runner.os }}-rust-advisory-${{ hashFiles('.code-foundry/src/runtime.mjs') }}
662
727
  restore-keys: |
663
728
  ${{ runner.os }}-rust-advisory-
664
729
  - name: Cache Rust builds
@@ -701,7 +766,7 @@ runs:
701
766
  REPO_FOUNDRY_INSTALL_PYTHON: ${{ inputs.install-python }}
702
767
  REPO_FOUNDRY_INSTALL_RUST: ${{ inputs.install-rust }}
703
768
  REPO_FOUNDRY_TASK: ${{ inputs.task }}
704
- run: bash .github/scripts/ci.sh install
769
+ run: node .code-foundry/src/runtime.mjs ci install
705
770
  - name: Measure Bun dependencies
706
771
  id: javascript-bun-cache
707
772
  if: >-
@@ -3,12 +3,17 @@ version: 1
3
3
  profile: auto
4
4
  languages: typescript
5
5
  features: all
6
+ codeql: auto
7
+ dependency_review: auto
6
8
  package_manager: bun
9
+ toolchain: auto
7
10
  runtime_repository: 0xPlayerOne/code-foundry
8
- runtime_ref: v0.22.2
11
+ runtime_ref: v0.26.0
9
12
  release_type: node
10
13
  npm_publish: true
11
14
  license: agpl-3.0-or-later
15
+ git_workflow: staging-release
16
+ merge_strategy: rebase
12
17
  runner: ubuntu-latest
13
18
  unit_runner: ubuntu-slim
14
19
  cache_packages: auto
@@ -53,23 +53,23 @@ jobs:
53
53
  path: .code-foundry
54
54
  sparse-checkout: |
55
55
  .github/actions
56
- .github/scripts
56
+ src/lib
57
+ src/runtime.mjs
57
58
  - name: Install runtime
58
59
  run: |
59
- mkdir -p .github/actions .github/scripts
60
+ mkdir -p .github/actions
60
61
  cp -R .code-foundry/.github/actions/. .github/actions/
61
- cp -R .code-foundry/.github/scripts/. .github/scripts/
62
62
  - name: Detect
63
63
  id: applicability
64
- run: bash .github/scripts/ci.sh should_run format >> "$GITHUB_OUTPUT"
65
- - name: Fast path
66
- if: steps.applicability.outputs.applicable == 'true'
67
- run: bash .github/scripts/format-fast-path.sh
64
+ run: node .code-foundry/src/runtime.mjs ci should_run format >> "$GITHUB_OUTPUT"
68
65
  - name: Setup
69
66
  if: steps.applicability.outputs.applicable == 'true'
70
67
  uses: ./.github/actions/setup
71
68
  with:
72
- install: 'false'
69
+ # Repository format scripts normally call a project-local formatter
70
+ # (for example, Prettier). Install dependencies before running them;
71
+ # otherwise a clean runner cannot resolve the declared tool.
72
+ install: 'true'
73
73
  cache-format: 'true'
74
74
  cache-lint: 'false'
75
75
  cache-build: 'false'
@@ -79,7 +79,7 @@ jobs:
79
79
  task-rust: 'false'
80
80
  - name: Format
81
81
  if: steps.applicability.outputs.applicable == 'true'
82
- run: bash .github/scripts/ci.sh format
82
+ run: node .code-foundry/src/runtime.mjs ci format
83
83
 
84
84
  lint:
85
85
  name: Lint
@@ -95,15 +95,15 @@ jobs:
95
95
  path: .code-foundry
96
96
  sparse-checkout: |
97
97
  .github/actions
98
- .github/scripts
98
+ src/lib
99
+ src/runtime.mjs
99
100
  - name: Install runtime
100
101
  run: |
101
- mkdir -p .github/actions .github/scripts
102
+ mkdir -p .github/actions
102
103
  cp -R .code-foundry/.github/actions/. .github/actions/
103
- cp -R .code-foundry/.github/scripts/. .github/scripts/
104
104
  - name: Detect
105
105
  id: applicability
106
- run: bash .github/scripts/ci.sh should_run lint >> "$GITHUB_OUTPUT"
106
+ run: node .code-foundry/src/runtime.mjs ci should_run lint >> "$GITHUB_OUTPUT"
107
107
  - name: Setup
108
108
  if: steps.applicability.outputs.applicable == 'true'
109
109
  uses: ./.github/actions/setup
@@ -113,7 +113,7 @@ jobs:
113
113
  task: lint
114
114
  - name: Lint
115
115
  if: steps.applicability.outputs.applicable == 'true'
116
- run: bash .github/scripts/ci.sh lint
116
+ run: node .code-foundry/src/runtime.mjs ci lint
117
117
 
118
118
  type-check:
119
119
  name: Type-Check
@@ -129,15 +129,15 @@ jobs:
129
129
  path: .code-foundry
130
130
  sparse-checkout: |
131
131
  .github/actions
132
- .github/scripts
132
+ src/lib
133
+ src/runtime.mjs
133
134
  - name: Install runtime
134
135
  run: |
135
- mkdir -p .github/actions .github/scripts
136
+ mkdir -p .github/actions
136
137
  cp -R .code-foundry/.github/actions/. .github/actions/
137
- cp -R .code-foundry/.github/scripts/. .github/scripts/
138
138
  - name: Detect
139
139
  id: applicability
140
- run: bash .github/scripts/ci.sh should_run type_check >> "$GITHUB_OUTPUT"
140
+ run: node .code-foundry/src/runtime.mjs ci should_run type_check >> "$GITHUB_OUTPUT"
141
141
  - name: Setup
142
142
  if: steps.applicability.outputs.applicable == 'true'
143
143
  uses: ./.github/actions/setup
@@ -147,11 +147,16 @@ jobs:
147
147
  task: type_check
148
148
  - name: Type-Check
149
149
  if: steps.applicability.outputs.applicable == 'true'
150
- run: bash .github/scripts/ci.sh type_check
150
+ run: node .code-foundry/src/runtime.mjs ci type_check
151
151
 
152
152
  build:
153
153
  name: Build
154
154
  runs-on: ${{ inputs.runner }}
155
+ env:
156
+ # Framework builds may validate server-side configuration at build time.
157
+ # Consumers can provide the real value; the fallback is intentionally
158
+ # CI-only and must never be used at runtime.
159
+ NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET || 'code-foundry-ci-placeholder-0123456789' }}
155
160
  steps:
156
161
  - name: Checkout
157
162
  uses: actions/checkout@v7
@@ -163,15 +168,15 @@ jobs:
163
168
  path: .code-foundry
164
169
  sparse-checkout: |
165
170
  .github/actions
166
- .github/scripts
171
+ src/lib
172
+ src/runtime.mjs
167
173
  - name: Install runtime
168
174
  run: |
169
- mkdir -p .github/actions .github/scripts
175
+ mkdir -p .github/actions
170
176
  cp -R .code-foundry/.github/actions/. .github/actions/
171
- cp -R .code-foundry/.github/scripts/. .github/scripts/
172
177
  - name: Detect
173
178
  id: applicability
174
- run: bash .github/scripts/ci.sh should_run build >> "$GITHUB_OUTPUT"
179
+ run: node .code-foundry/src/runtime.mjs ci should_run build >> "$GITHUB_OUTPUT"
175
180
  - name: Setup
176
181
  if: steps.applicability.outputs.applicable == 'true'
177
182
  uses: ./.github/actions/setup
@@ -181,4 +186,4 @@ jobs:
181
186
  task: build
182
187
  - name: Build
183
188
  if: steps.applicability.outputs.applicable == 'true'
184
- run: bash .github/scripts/ci.sh build
189
+ run: node .code-foundry/src/runtime.mjs ci build
@@ -16,6 +16,6 @@ jobs:
16
16
  uses: ./.github/workflows/ci.yml
17
17
  with:
18
18
  runtime-repository: 0xPlayerOne/code-foundry
19
- runtime-ref: v0.22.0
19
+ runtime-ref: staging
20
20
  runner: ubuntu-latest
21
21
  secrets: inherit
@@ -41,6 +41,7 @@ jobs:
41
41
  timeout-minutes: 10
42
42
  outputs:
43
43
  languages: ${{ steps.languages.outputs.languages }}
44
+ enabled: ${{ steps.languages.outputs.enabled }}
44
45
  code_security: ${{ steps.security.outputs.status }}
45
46
  actions_available: ${{ steps.languages.outputs.actions_available }}
46
47
  actions_changed: ${{ steps.languages.outputs.actions_changed }}
@@ -61,14 +62,13 @@ jobs:
61
62
  GH_TOKEN: ${{ github.token }}
62
63
  run: |
63
64
  status="disabled"
64
- if [ "${{ github.event.repository.private }}" != "true" ]; then
65
+ if [ "${{ github.event.repository.visibility }}" = "public" ]; then
65
66
  status="enabled"
66
67
  else
67
68
  status="$(gh api "repos/${GITHUB_REPOSITORY}" --jq '.security_and_analysis.code_security.status // "disabled"' 2>/dev/null || printf 'disabled')"
68
69
  fi
69
70
  printf 'status=%s\n' "$status" >> "$GITHUB_OUTPUT"
70
71
  - name: Checkout
71
- if: ${{ !github.event.repository.private || steps.security.outputs.status == 'enabled' }}
72
72
  uses: actions/checkout@v7
73
73
  with:
74
74
  fetch-depth: 2
@@ -85,7 +85,6 @@ jobs:
85
85
  package-lock.json
86
86
  sparse-checkout-cone-mode: false
87
87
  - name: Runtime
88
- if: ${{ !github.event.repository.private || steps.security.outputs.status == 'enabled' }}
89
88
  uses: actions/checkout@v7
90
89
  with:
91
90
  repository: ${{ inputs.runtime-repository }}
@@ -93,31 +92,26 @@ jobs:
93
92
  path: .code-foundry
94
93
  sparse-checkout: |
95
94
  .github/actions
96
- .github/scripts
95
+ src/lib
96
+ src/runtime.mjs
97
97
  - name: Install runtime
98
- if: ${{ !github.event.repository.private || steps.security.outputs.status == 'enabled' }}
99
98
  run: |
100
- mkdir -p .github/actions .github/scripts
99
+ mkdir -p .github/actions
101
100
  cp -R .code-foundry/.github/actions/. .github/actions/
102
- cp -R .code-foundry/.github/scripts/. .github/scripts/
103
101
  - id: languages
104
102
  name: Detect languages
105
103
  env:
106
104
  CODEQL_BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
107
105
  REPO_FOUNDRY_CODE_SECURITY: ${{ steps.security.outputs.status }}
108
106
  REPO_FOUNDRY_PRIVATE: ${{ github.event.repository.private }}
109
- run: |
110
- if [ "$REPO_FOUNDRY_PRIVATE" = "true" ] && [ "$REPO_FOUNDRY_CODE_SECURITY" != "enabled" ]; then
111
- echo 'languages=[]' >> "$GITHUB_OUTPUT"
112
- else
113
- bash .github/scripts/codeql-languages.sh
114
- fi
107
+ REPO_FOUNDRY_VISIBILITY: ${{ github.event.repository.visibility }}
108
+ run: node .code-foundry/src/runtime.mjs codeql
115
109
 
116
110
  analyze-actions:
117
111
  name: Analyze (Actions)
118
112
  needs: detect
119
113
  if: >-
120
- ( !github.event.repository.private || needs.detect.outputs.code_security == 'enabled' ) &&
114
+ needs.detect.outputs.enabled == 'true' &&
121
115
  needs.detect.outputs.actions_available == 'true' &&
122
116
  needs.detect.outputs.actions_changed == 'true'
123
117
  runs-on: ${{ inputs.runner }}
@@ -133,12 +127,12 @@ jobs:
133
127
  path: .code-foundry
134
128
  sparse-checkout: |
135
129
  .github/actions
136
- .github/scripts
130
+ src/lib
131
+ src/runtime.mjs
137
132
  - name: Install runtime
138
133
  run: |
139
- mkdir -p .github/actions .github/scripts
134
+ mkdir -p .github/actions
140
135
  cp -R .code-foundry/.github/actions/. .github/actions/
141
- cp -R .code-foundry/.github/scripts/. .github/scripts/
142
136
  - name: Analyze
143
137
  uses: ./.github/actions/codeql
144
138
  with:
@@ -150,7 +144,7 @@ jobs:
150
144
  name: Analyze (TypeScript)
151
145
  needs: detect
152
146
  if: >-
153
- ( !github.event.repository.private || needs.detect.outputs.code_security == 'enabled' ) &&
147
+ needs.detect.outputs.enabled == 'true' &&
154
148
  needs.detect.outputs.javascript_available == 'true' &&
155
149
  needs.detect.outputs.javascript_changed == 'true'
156
150
  runs-on: ${{ inputs.runner }}
@@ -166,12 +160,12 @@ jobs:
166
160
  path: .code-foundry
167
161
  sparse-checkout: |
168
162
  .github/actions
169
- .github/scripts
163
+ src/lib
164
+ src/runtime.mjs
170
165
  - name: Install runtime
171
166
  run: |
172
- mkdir -p .github/actions .github/scripts
167
+ mkdir -p .github/actions
173
168
  cp -R .code-foundry/.github/actions/. .github/actions/
174
- cp -R .code-foundry/.github/scripts/. .github/scripts/
175
169
  - name: Analyze
176
170
  uses: ./.github/actions/codeql
177
171
  with:
@@ -183,7 +177,7 @@ jobs:
183
177
  name: Analyze (Python)
184
178
  needs: detect
185
179
  if: >-
186
- ( !github.event.repository.private || needs.detect.outputs.code_security == 'enabled' ) &&
180
+ needs.detect.outputs.enabled == 'true' &&
187
181
  needs.detect.outputs.python_available == 'true' &&
188
182
  needs.detect.outputs.python_changed == 'true'
189
183
  runs-on: ${{ inputs.runner }}
@@ -199,12 +193,12 @@ jobs:
199
193
  path: .code-foundry
200
194
  sparse-checkout: |
201
195
  .github/actions
202
- .github/scripts
196
+ src/lib
197
+ src/runtime.mjs
203
198
  - name: Install runtime
204
199
  run: |
205
- mkdir -p .github/actions .github/scripts
200
+ mkdir -p .github/actions
206
201
  cp -R .code-foundry/.github/actions/. .github/actions/
207
- cp -R .code-foundry/.github/scripts/. .github/scripts/
208
202
  - name: Analyze
209
203
  uses: ./.github/actions/codeql
210
204
  with:
@@ -216,7 +210,7 @@ jobs:
216
210
  name: Analyze (Rust)
217
211
  needs: detect
218
212
  if: >-
219
- ( !github.event.repository.private || needs.detect.outputs.code_security == 'enabled' ) &&
213
+ needs.detect.outputs.enabled == 'true' &&
220
214
  needs.detect.outputs.rust_available == 'true' &&
221
215
  needs.detect.outputs.rust_changed == 'true'
222
216
  runs-on: ${{ inputs.runner }}
@@ -232,12 +226,12 @@ jobs:
232
226
  path: .code-foundry
233
227
  sparse-checkout: |
234
228
  .github/actions
235
- .github/scripts
229
+ src/lib
230
+ src/runtime.mjs
236
231
  - name: Install runtime
237
232
  run: |
238
- mkdir -p .github/actions .github/scripts
233
+ mkdir -p .github/actions
239
234
  cp -R .code-foundry/.github/actions/. .github/actions/
240
- cp -R .code-foundry/.github/scripts/. .github/scripts/
241
235
  - name: Analyze
242
236
  uses: ./.github/actions/codeql
243
237
  with:
@@ -21,6 +21,6 @@ jobs:
21
21
  uses: ./.github/workflows/codeql.yml
22
22
  with:
23
23
  runtime-repository: 0xPlayerOne/code-foundry
24
- runtime-ref: v0.22.0
24
+ runtime-ref: staging
25
25
  runner: ubuntu-latest
26
26
  secrets: inherit
@@ -29,7 +29,7 @@ jobs:
29
29
  id: check-pr
30
30
  run: |
31
31
  BRANCH="${{ github.ref_name }}"
32
- EXISTING=$(gh pr list --limit 1 --base staging --head "$BRANCH" --state open --json number,title 2>/dev/null | jq 'length')
32
+ EXISTING=$(gh pr list --limit 1 --base staging --head "$BRANCH" --state open --json number,title 2>/dev/null | node -e 'let d=""; process.stdin.on("data", c => d += c).on("end", () => console.log(JSON.parse(d || "[]").length))')
33
33
  echo "existing=$EXISTING" >> "$GITHUB_OUTPUT"
34
34
 
35
35
  - name: Create
@@ -51,7 +51,7 @@ jobs:
51
51
  if: steps.check-pr.outputs.existing == '0'
52
52
  run: |
53
53
  BRANCH="${{ github.ref_name }}"
54
- PR_NUMBER=$(gh pr list --limit 1 --base staging --head "$BRANCH" --state open --json number 2>/dev/null | jq '.[0].number')
54
+ PR_NUMBER=$(gh pr list --limit 1 --base staging --head "$BRANCH" --state open --json number 2>/dev/null | node -e 'let d=""; process.stdin.on("data", c => d += c).on("end", () => console.log(JSON.parse(d || "[]")[0]?.number || ""))')
55
55
  if [ -n "$PR_NUMBER" ]; then
56
56
  gh pr ready "$PR_NUMBER"
57
57
  fi
@@ -35,7 +35,7 @@ jobs:
35
35
  --base main \
36
36
  --head staging \
37
37
  --state open \
38
- --json number | jq 'length')
38
+ --json number | node -e 'let d=""; process.stdin.on("data", c => d += c).on("end", () => console.log(JSON.parse(d || "[]").length))')
39
39
  COMPARE_URL="repos/${GITHUB_REPOSITORY}/compare/main...staging"
40
40
  TOTAL_COMMITS=$(gh api "$COMPARE_URL?per_page=1" --jq '.total_commits // 0')
41
41
  echo "existing=$EXISTING" >> "$GITHUB_OUTPUT"
@@ -53,12 +53,12 @@ jobs:
53
53
  COMPARE_URL="repos/${GITHUB_REPOSITORY}/compare/main...staging"
54
54
  COMPARE_FILE="$RUNNER_TEMP/release-compare.json"
55
55
  gh api "$COMPARE_URL?per_page=100" > "$COMPARE_FILE"
56
- TOTAL_COMMITS=$(jq -r '.total_commits // 0' "$COMPARE_FILE")
56
+ TOTAL_COMMITS=$(node -e 'const d=require(process.argv[1]); console.log(d.total_commits || 0)' "$COMPARE_FILE")
57
57
  if [ "$TOTAL_COMMITS" -gt 100 ]; then
58
58
  LAST_PAGE=$(( (TOTAL_COMMITS + 99) / 100 ))
59
59
  gh api "$COMPARE_URL?per_page=100&page=$LAST_PAGE" > "$COMPARE_FILE"
60
60
  fi
61
- COMMITS=$(jq -r '.commits[] | "- \(.commit.message | split("\\n")[0]) (\(.sha[0:7]))"' "$COMPARE_FILE")
61
+ COMMITS=$(node -e 'const d=require(process.argv[1]); for (const c of d.commits || []) console.log(`- ${c.commit.message.split("\\n")[0]} (${c.sha.slice(0, 7)})`)' "$COMPARE_FILE")
62
62
  if [ -z "$COMMITS" ]; then
63
63
  COMMITS='- No commits found since main.'
64
64
  fi
@@ -87,7 +87,7 @@ jobs:
87
87
  ### Validation
88
88
 
89
89
  - Required CI, test, security, and CodeQL checks must pass before merge.
90
- - Merge with **rebase** to preserve the linear Conventional Commit history.
90
+ - Merge using the repository's configured \`merge_strategy\` (default: **rebase**).
91
91
  - After merge, Release Please opens a separate versioned release PR with the changelog.
92
92
  EOF
93
93
 
@@ -41,36 +41,24 @@ jobs:
41
41
  filter: blob:none
42
42
  - name: Detect release profile
43
43
  id: profile
44
- shell: bash
45
44
  run: |
46
- if [ -x .github/scripts/profile.sh ]; then
47
- release_type="$(bash .github/scripts/profile.sh get release_type)"
48
- npm_publish="$(bash .github/scripts/profile.sh get npm_publish)"
49
- else
50
- config_file=.github/code-foundry.yml
51
- release_type="$(awk -F': ' '/^release_type:/ {print $2; exit}' "$config_file" 2>/dev/null || true)"
52
- npm_publish="$(awk -F': ' '/^npm_publish:/ {print $2; exit}' "$config_file" 2>/dev/null || true)"
53
- fi
54
- [ -n "$release_type" ] || release_type=auto
55
- [ -n "$npm_publish" ] || npm_publish=false
56
-
57
- if [ "$release_type" = auto ]; then
58
- if [ -f package.json ]; then release_type=node
59
- elif [ -f pyproject.toml ]; then release_type=python
60
- elif [ -f Cargo.toml ]; then release_type=rust
61
- elif [ -f version.txt ]; then release_type=simple
62
- else release_type=none
63
- fi
64
- fi
65
-
66
- case "$release_type" in
67
- node|python|rust|simple) ;;
68
- none) npm_publish=false ;;
69
- *) echo "Unsupported release_type: $release_type" >&2; exit 2 ;;
70
- esac
71
- if [ ! -f package.json ]; then npm_publish=false; fi
72
- printf 'release_type=%s\n' "$release_type" >> "$GITHUB_OUTPUT"
73
- printf 'npm_publish=%s\n' "$npm_publish" >> "$GITHUB_OUTPUT"
45
+ node <<'NODE'
46
+ const fs = require('node:fs')
47
+ const config = fs.existsSync('.github/code-foundry.yml')
48
+ ? Object.fromEntries(fs.readFileSync('.github/code-foundry.yml', 'utf8').split(/\r?\n/).flatMap((line) => {
49
+ const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*?)\s*$/)
50
+ return match ? [[match[1], match[2].replace(/\s+#.*$/, '').replace(/^['"]|['"]$/g, '')]] : []
51
+ }))
52
+ : {}
53
+ let releaseType = config.release_type || 'auto'
54
+ let npmPublish = config.npm_publish || 'false'
55
+ if (releaseType === 'auto') {
56
+ releaseType = fs.existsSync('package.json') ? 'node' : fs.existsSync('pyproject.toml') ? 'python' : fs.existsSync('Cargo.toml') ? 'rust' : fs.existsSync('version.txt') ? 'simple' : 'none'
57
+ }
58
+ if (!['node', 'python', 'rust', 'simple', 'none'].includes(releaseType)) throw new Error(`Unsupported release_type: ${releaseType}`)
59
+ if (releaseType === 'none' || !fs.existsSync('package.json')) npmPublish = 'false'
60
+ fs.appendFileSync(process.env.GITHUB_OUTPUT, `release_type=${releaseType}\nnpm_publish=${npmPublish}\n`)
61
+ NODE
74
62
  - name: Release Please
75
63
  id: release
76
64
  if: steps.profile.outputs.release_type != 'none'