code-foundry 1.53.2 → 1.53.4
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.
- package/.github/workflows/ci.yml +8 -8
- package/.github/workflows/eval.yml +2 -2
- package/.github/workflows/test.yml +13 -12
- package/.github/workflows/validation-billing.yml +11 -10
- package/CHANGELOG.md +15 -15
- package/docs/CACHING.md +9 -1
- package/docs/CONFIGURATION.md +1 -1
- package/docs/PERFORMANCE.md +1 -1
- package/package.json +1 -1
- package/src/lib/run-concurrent.mjs +45 -0
- package/src/runtime-core.mjs +24 -5
package/.github/workflows/ci.yml
CHANGED
|
@@ -129,8 +129,8 @@ jobs:
|
|
|
129
129
|
if-no-files-found: error
|
|
130
130
|
retention-days: 14
|
|
131
131
|
|
|
132
|
-
- name: Save
|
|
133
|
-
uses: ./.github/actions/
|
|
132
|
+
- name: Save task caches
|
|
133
|
+
uses: ./.github/actions/cache-save
|
|
134
134
|
|
|
135
135
|
lint:
|
|
136
136
|
name: Lint
|
|
@@ -193,8 +193,8 @@ jobs:
|
|
|
193
193
|
if-no-files-found: error
|
|
194
194
|
retention-days: 14
|
|
195
195
|
|
|
196
|
-
- name: Save
|
|
197
|
-
uses: ./.github/actions/
|
|
196
|
+
- name: Save task caches
|
|
197
|
+
uses: ./.github/actions/cache-save
|
|
198
198
|
|
|
199
199
|
type-check:
|
|
200
200
|
name: Type-Check
|
|
@@ -262,8 +262,8 @@ jobs:
|
|
|
262
262
|
if-no-files-found: error
|
|
263
263
|
retention-days: 14
|
|
264
264
|
|
|
265
|
-
- name: Save
|
|
266
|
-
uses: ./.github/actions/
|
|
265
|
+
- name: Save task caches
|
|
266
|
+
uses: ./.github/actions/cache-save
|
|
267
267
|
|
|
268
268
|
build:
|
|
269
269
|
name: Build
|
|
@@ -357,5 +357,5 @@ jobs:
|
|
|
357
357
|
if-no-files-found: error
|
|
358
358
|
retention-days: 14
|
|
359
359
|
|
|
360
|
-
- name: Save
|
|
361
|
-
uses: ./.github/actions/
|
|
360
|
+
- name: Save task caches
|
|
361
|
+
uses: ./.github/actions/cache-save
|
|
@@ -166,8 +166,8 @@ jobs:
|
|
|
166
166
|
if-no-files-found: ignore
|
|
167
167
|
retention-days: 14
|
|
168
168
|
|
|
169
|
-
- name: Save
|
|
170
|
-
uses: ./.github/actions/
|
|
169
|
+
- name: Save task caches
|
|
170
|
+
uses: ./.github/actions/cache-save
|
|
171
171
|
|
|
172
172
|
performance:
|
|
173
173
|
name: Performance
|
|
@@ -255,8 +255,8 @@ jobs:
|
|
|
255
255
|
if-no-files-found: ignore
|
|
256
256
|
retention-days: 14
|
|
257
257
|
|
|
258
|
-
- name: Save
|
|
259
|
-
uses: ./.github/actions/
|
|
258
|
+
- name: Save task caches
|
|
259
|
+
uses: ./.github/actions/cache-save
|
|
260
260
|
|
|
261
261
|
integration:
|
|
262
262
|
name: Integration
|
|
@@ -332,8 +332,8 @@ jobs:
|
|
|
332
332
|
if-no-files-found: error
|
|
333
333
|
retention-days: 14
|
|
334
334
|
|
|
335
|
-
- name: Save
|
|
336
|
-
uses: ./.github/actions/
|
|
335
|
+
- name: Save task caches
|
|
336
|
+
uses: ./.github/actions/cache-save
|
|
337
337
|
|
|
338
338
|
integration-sharded:
|
|
339
339
|
name: Integration shard
|
|
@@ -412,8 +412,8 @@ jobs:
|
|
|
412
412
|
if-no-files-found: error
|
|
413
413
|
retention-days: 14
|
|
414
414
|
|
|
415
|
-
- name: Save
|
|
416
|
-
uses: ./.github/actions/
|
|
415
|
+
- name: Save task caches
|
|
416
|
+
uses: ./.github/actions/cache-save
|
|
417
417
|
|
|
418
418
|
e2e:
|
|
419
419
|
name: E2E
|
|
@@ -464,6 +464,7 @@ jobs:
|
|
|
464
464
|
if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false' && steps.applicability.outputs.browser == 'true'
|
|
465
465
|
uses: ./.github/actions/cache
|
|
466
466
|
with:
|
|
467
|
+
id: e2e-browsers
|
|
467
468
|
save: ${{ github.event_name == 'push' }}
|
|
468
469
|
path: |
|
|
469
470
|
~/.cache/ms-playwright
|
|
@@ -508,8 +509,8 @@ jobs:
|
|
|
508
509
|
if-no-files-found: error
|
|
509
510
|
retention-days: 14
|
|
510
511
|
|
|
511
|
-
- name: Save
|
|
512
|
-
uses: ./.github/actions/
|
|
512
|
+
- name: Save task caches
|
|
513
|
+
uses: ./.github/actions/cache-save
|
|
513
514
|
|
|
514
515
|
smoke:
|
|
515
516
|
name: Smoke
|
|
@@ -581,5 +582,5 @@ jobs:
|
|
|
581
582
|
if-no-files-found: error
|
|
582
583
|
retention-days: 14
|
|
583
584
|
|
|
584
|
-
- name: Save
|
|
585
|
-
uses: ./.github/actions/
|
|
585
|
+
- name: Save task caches
|
|
586
|
+
uses: ./.github/actions/cache-save
|
|
@@ -543,8 +543,8 @@ jobs:
|
|
|
543
543
|
if-no-files-found: error
|
|
544
544
|
retention-days: 14
|
|
545
545
|
|
|
546
|
-
- name: Save
|
|
547
|
-
uses: ./.github/actions/
|
|
546
|
+
- name: Save task caches
|
|
547
|
+
uses: ./.github/actions/cache-save
|
|
548
548
|
|
|
549
549
|
lint:
|
|
550
550
|
name: Lint
|
|
@@ -614,8 +614,8 @@ jobs:
|
|
|
614
614
|
if-no-files-found: error
|
|
615
615
|
retention-days: 14
|
|
616
616
|
|
|
617
|
-
- name: Save
|
|
618
|
-
uses: ./.github/actions/
|
|
617
|
+
- name: Save task caches
|
|
618
|
+
uses: ./.github/actions/cache-save
|
|
619
619
|
|
|
620
620
|
type-check:
|
|
621
621
|
name: Type-Check
|
|
@@ -686,8 +686,8 @@ jobs:
|
|
|
686
686
|
if-no-files-found: error
|
|
687
687
|
retention-days: 14
|
|
688
688
|
|
|
689
|
-
- name: Save
|
|
690
|
-
uses: ./.github/actions/
|
|
689
|
+
- name: Save task caches
|
|
690
|
+
uses: ./.github/actions/cache-save
|
|
691
691
|
|
|
692
692
|
unit:
|
|
693
693
|
name: Unit
|
|
@@ -782,8 +782,8 @@ jobs:
|
|
|
782
782
|
if-no-files-found: ignore
|
|
783
783
|
retention-days: 14
|
|
784
784
|
|
|
785
|
-
- name: Save
|
|
786
|
-
uses: ./.github/actions/
|
|
785
|
+
- name: Save task caches
|
|
786
|
+
uses: ./.github/actions/cache-save
|
|
787
787
|
|
|
788
788
|
e2e:
|
|
789
789
|
name: E2E
|
|
@@ -838,6 +838,7 @@ jobs:
|
|
|
838
838
|
if: steps.applicability.outputs.applicable == 'true' && steps.applicability.outputs.affected != 'false' && steps.applicability.outputs.browser == 'true'
|
|
839
839
|
uses: ./.github/actions/cache
|
|
840
840
|
with:
|
|
841
|
+
id: e2e-browsers
|
|
841
842
|
save: ${{ github.event_name == 'push' }}
|
|
842
843
|
path: |
|
|
843
844
|
~/.cache/ms-playwright
|
|
@@ -882,8 +883,8 @@ jobs:
|
|
|
882
883
|
if-no-files-found: error
|
|
883
884
|
retention-days: 14
|
|
884
885
|
|
|
885
|
-
- name: Save
|
|
886
|
-
uses: ./.github/actions/
|
|
886
|
+
- name: Save task caches
|
|
887
|
+
uses: ./.github/actions/cache-save
|
|
887
888
|
|
|
888
889
|
# Profile and dependency audit merged into one job. The split orchestrators
|
|
889
890
|
# run a profile job that feeds an audit matrix; here the language blocks run
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.53.4](https://github.com/0xPlayerOne/code-foundry/compare/v1.53.3...v1.53.4) (2026-10-30)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Performance
|
|
7
|
+
|
|
8
|
+
* **ci:** run mixed unit runners concurrently ([#821](https://github.com/0xPlayerOne/code-foundry/issues/821)) ([dac0d93](https://github.com/0xPlayerOne/code-foundry/commit/dac0d9313cc2fc6309e0f55aa45274e3dbbff767))
|
|
9
|
+
|
|
10
|
+
## [1.53.3](https://github.com/0xPlayerOne/code-foundry/compare/v1.53.2...v1.53.3) (2026-10-30)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* save repository caches through an explicit save action ([#819](https://github.com/0xPlayerOne/code-foundry/issues/819)) ([a21f1d0](https://github.com/0xPlayerOne/code-foundry/commit/a21f1d0c153e14252bc784f301379029026121da))
|
|
16
|
+
|
|
3
17
|
## [1.53.2](https://github.com/0xPlayerOne/code-foundry/compare/v1.53.1...v1.53.2) (2026-10-30)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -136,23 +150,9 @@
|
|
|
136
150
|
|
|
137
151
|
* **release:** hydrate audit blobs and refresh changing PR state ([#779](https://github.com/0xPlayerOne/code-foundry/issues/779)) ([8734ed7](https://github.com/0xPlayerOne/code-foundry/commit/8734ed77d159818cd5ff613f40a5dab796789d8a))
|
|
138
152
|
|
|
139
|
-
## [1.48.7](https://github.com/0xPlayerOne/code-foundry/compare/v1.48.6...v1.48.7) (2026-10-23)
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
### Bug Fixes
|
|
143
|
-
|
|
144
|
-
* **release:** sync bun.lock workspace versions on generated release PRs ([#777](https://github.com/0xPlayerOne/code-foundry/issues/777)) ([b24bfae](https://github.com/0xPlayerOne/code-foundry/commit/b24bfae309ac7003fcc4cd57f79ddc418c27b039))
|
|
145
|
-
|
|
146
|
-
## [1.48.6](https://github.com/0xPlayerOne/code-foundry/compare/v1.48.5...v1.48.6) (2026-10-23)
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
### Bug Fixes
|
|
150
|
-
|
|
151
|
-
* **release:** audit generated release content for stale snapshots ([#775](https://github.com/0xPlayerOne/code-foundry/issues/775)) ([f842c27](https://github.com/0xPlayerOne/code-foundry/commit/f842c271e6b270b63a6d9b839795a849237c7a7d))
|
|
152
|
-
|
|
153
153
|
<!-- code-foundry: packaged changelog -->
|
|
154
154
|
|
|
155
155
|
---
|
|
156
156
|
|
|
157
|
-
This packaged changelog lists the 20 most recent releases;
|
|
157
|
+
This packaged changelog lists the 20 most recent releases; 275 older releases are omitted to keep the package small.
|
|
158
158
|
See the [full changelog](https://github.com/0xPlayerOne/code-foundry/blob/main/CHANGELOG.md) for the complete history.
|
package/docs/CACHING.md
CHANGED
|
@@ -11,6 +11,13 @@ Repositories should measure before enabling large installed-tree or build
|
|
|
11
11
|
caches. Set repository variables such as `REPO_FOUNDRY_CACHE_PACKAGES` and
|
|
12
12
|
`REPO_FOUNDRY_CACHE_BUILD` only when a repeatable warm-cache benefit is proven.
|
|
13
13
|
|
|
14
|
+
These caches are restored on every event and saved on push only, so pull
|
|
15
|
+
requests and scheduled runs cannot poison them. The setup action restores them
|
|
16
|
+
and publishes a save contract; the `.github/actions/cache-save` action at the
|
|
17
|
+
end of each task job saves every published cache that did not restore an exact
|
|
18
|
+
key. Custom workflows that use `.github/actions/setup` must call it after their
|
|
19
|
+
tasks, or nothing is saved.
|
|
20
|
+
|
|
14
21
|
## Turborepo and Vercel Remote Caching
|
|
15
22
|
|
|
16
23
|
Turborepo repositories can opt into Vercel Remote Caching with:
|
|
@@ -35,7 +42,8 @@ When opted in, the setup action:
|
|
|
35
42
|
- restores `node_modules/.vite/task-cache` as its last step, after Install and
|
|
36
43
|
after every step that archives `node_modules` (Install can replace it);
|
|
37
44
|
- publishes a cache path, key, and save-intent contract for the explicit
|
|
38
|
-
`.github/actions/
|
|
45
|
+
`.github/actions/cache-save` action, which also saves the repository caches,
|
|
46
|
+
to use after repository tasks;
|
|
39
47
|
- saves it push-only, so pull requests and scheduled runs cannot poison it;
|
|
40
48
|
- keeps it out of the generic JavaScript build-state archive.
|
|
41
49
|
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -350,7 +350,7 @@ behavior:
|
|
|
350
350
|
(not a config key). It controls the local Vite+ task cache only when
|
|
351
351
|
`monorepo_tool: vite-plus` is set.
|
|
352
352
|
- Custom workflows using the setup action must add
|
|
353
|
-
`.github/actions/
|
|
353
|
+
`.github/actions/cache-save` after task execution. The generated
|
|
354
354
|
Code Foundry workflows already include this save boundary; see
|
|
355
355
|
[Caching and remote caching](CACHING.md).
|
|
356
356
|
|
package/docs/PERFORMANCE.md
CHANGED
|
@@ -31,7 +31,7 @@ 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
32
|
and 118 files.
|
|
33
33
|
|
|
34
|
-
v1.
|
|
34
|
+
v1.53.3 main no-changelog, plus the concurrent unit runner (`src/lib/run-concurrent.mjs`): 317,788 packed, 1,226,187 unpacked, 120 files. Limits: 318,000 packed, 1,227,000 unpacked, 120 files.
|
|
35
35
|
|
|
36
36
|
The published package ships a changelog trimmed to the 20 most recent releases
|
|
37
37
|
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.53.
|
|
3
|
+
"version": "1.53.4",
|
|
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": {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Runs independent test commands at the same time so a mixed repository's
|
|
3
|
+
// unit wall time is its slowest runner, not the sum of all of them. Each line
|
|
4
|
+
// of output is prefixed with its runner's label, and the exit status is the
|
|
5
|
+
// first failing command's in the order given, so the result stays stable.
|
|
6
|
+
import { spawn } from 'node:child_process'
|
|
7
|
+
import { createInterface } from 'node:readline'
|
|
8
|
+
import { resolve } from 'node:path'
|
|
9
|
+
import { pathToFileURL } from 'node:url'
|
|
10
|
+
|
|
11
|
+
/** @typedef {{ label: string, command: string, args: string[] }} Job */
|
|
12
|
+
|
|
13
|
+
/** @param {Job} job @returns {Promise<number>} */
|
|
14
|
+
function runJob(job) {
|
|
15
|
+
return new Promise((resolvePromise) => {
|
|
16
|
+
const child = spawn(job.command, job.args, {
|
|
17
|
+
cwd: process.cwd(),
|
|
18
|
+
env: process.env,
|
|
19
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
20
|
+
})
|
|
21
|
+
const prefix = `[${job.label}] `
|
|
22
|
+
/** @param {import('node:stream').Readable} stream @param {NodeJS.WriteStream} sink */
|
|
23
|
+
const relay = (stream, sink) =>
|
|
24
|
+
createInterface({ input: stream, crlfDelay: Infinity }).on('line', (line) =>
|
|
25
|
+
sink.write(`${prefix}${line}\n`)
|
|
26
|
+
)
|
|
27
|
+
relay(child.stdout, process.stdout)
|
|
28
|
+
relay(child.stderr, process.stderr)
|
|
29
|
+
child.on('error', (error) => {
|
|
30
|
+
process.stderr.write(`${prefix}${error.message}\n`)
|
|
31
|
+
resolvePromise(1)
|
|
32
|
+
})
|
|
33
|
+
child.on('close', (code, signal) => resolvePromise(signal ? 1 : (code ?? 1)))
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** @param {Job[]} jobs */
|
|
38
|
+
export async function runConcurrent(jobs) {
|
|
39
|
+
const statuses = await Promise.all(jobs.map(runJob))
|
|
40
|
+
return statuses.find((status) => status !== 0) ?? 0
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
|
|
44
|
+
process.exitCode = await runConcurrent(JSON.parse(process.argv[2] ?? '[]'))
|
|
45
|
+
}
|
package/src/runtime-core.mjs
CHANGED
|
@@ -835,8 +835,18 @@ function ci(task) {
|
|
|
835
835
|
e2e: ['test:e2e', 'e2e'],
|
|
836
836
|
smoke: ['test:smoke', 'smoke'],
|
|
837
837
|
}
|
|
838
|
-
|
|
839
|
-
|
|
838
|
+
// Unit runners share no state, so they run together and the task takes as
|
|
839
|
+
// long as its slowest runner. Other categories may share services or ports
|
|
840
|
+
// and keep running one after another.
|
|
841
|
+
/** @type {{ label: string, command: string, args: string[] }[]} */
|
|
842
|
+
const jobs = []
|
|
843
|
+
/** @param {string} label @param {string} command @param {string[]} args */
|
|
844
|
+
const queue = (label, command, args) =>
|
|
845
|
+
task === 'unit' ? jobs.push({ label, command, args }) : run(command, args)
|
|
846
|
+
const scriptName = scriptsByTask[task]?.find((candidate) => hasScript(candidate))
|
|
847
|
+
const [scriptManager, scriptArgs] = scriptName ? packageCommand(['run', scriptName]) : [null, []]
|
|
848
|
+
const scripted = Boolean(scriptManager)
|
|
849
|
+
if (scriptName && scriptManager) queue(scriptName, scriptManager, scriptArgs)
|
|
840
850
|
const testFiles = taskTestFiles(/** @type {'unit'|'integration'|'e2e'|'smoke'} */ (task))
|
|
841
851
|
const javascriptTests = testFiles.filter((file) => /\.(?:[cm]?[jt]sx?)$/i.test(file))
|
|
842
852
|
const pythonTests = testFiles.filter((file) => /\.py$/i.test(file))
|
|
@@ -851,14 +861,16 @@ function ci(task) {
|
|
|
851
861
|
(hasLanguage('typescript') || hasLanguage('javascript') || hasLanguage('solidity')) &&
|
|
852
862
|
hasRootJavascriptProject()
|
|
853
863
|
) {
|
|
854
|
-
if (javascriptTests.length > 0 || task === 'unit')
|
|
864
|
+
if (javascriptTests.length > 0 || task === 'unit')
|
|
865
|
+
queue('bun', 'bun', ['test', ...javascriptTests])
|
|
855
866
|
}
|
|
856
867
|
|
|
857
868
|
if (hasLanguage('python') && hasRootPythonProject()) {
|
|
858
869
|
const python = existsSync(resolve(root, '.venv/bin/python'))
|
|
859
870
|
? resolve(root, '.venv/bin/python')
|
|
860
871
|
: 'python'
|
|
861
|
-
if (pythonTests.length > 0 || task === 'unit')
|
|
872
|
+
if (pythonTests.length > 0 || task === 'unit')
|
|
873
|
+
queue('pytest', python, ['-m', 'pytest', ...pythonTests])
|
|
862
874
|
}
|
|
863
875
|
|
|
864
876
|
if (hasLanguage('rust') && hasRootRustProject()) {
|
|
@@ -872,7 +884,7 @@ function ci(task) {
|
|
|
872
884
|
const args = [...testArgs]
|
|
873
885
|
if (existsSync(resolve(root, 'src/lib.rs'))) args.push('--lib')
|
|
874
886
|
if (existsSync(resolve(root, 'src/main.rs'))) args.push('--bin', packageName())
|
|
875
|
-
|
|
887
|
+
queue('cargo', 'cargo', args)
|
|
876
888
|
} else {
|
|
877
889
|
// Keep --test selection narrow; --tests includes unit targets.
|
|
878
890
|
const targets = rustTests.flatMap((file) => {
|
|
@@ -882,6 +894,13 @@ function ci(task) {
|
|
|
882
894
|
if (targets.length > 0) run('cargo', [...testArgs, ...targets])
|
|
883
895
|
}
|
|
884
896
|
}
|
|
897
|
+
|
|
898
|
+
if (jobs.length === 1) run(jobs[0].command, jobs[0].args)
|
|
899
|
+
else if (jobs.length > 1)
|
|
900
|
+
run(process.execPath, [
|
|
901
|
+
fileURLToPath(new URL('./lib/run-concurrent.mjs', import.meta.url)),
|
|
902
|
+
JSON.stringify(jobs),
|
|
903
|
+
])
|
|
885
904
|
}
|
|
886
905
|
|
|
887
906
|
function packageName() {
|