dtu-github-actions@0.16.0
Minor Changes
-
c8da13a: Add
agent-ci run --var-file <path|->for loading workflow variables from JSON files or GitHub CLIgh variable list --json name,valueoutput piped on stdin. Explicit--var KEY=VALUEflags override file-provided values.Refs #358.
-
ab075d9: chore: require Node 24 and drop
tsxNode 24 ships native TypeScript stripping as a stable feature, so we no
longer need thetsxruntime to execute.tsfiles. Everytsx foo.ts
invocation in package scripts becomesnode foo.ts.tsxis removed
fromdevDependenciesin every workspace.To make this work with the codebase's existing import convention,
TypeScript is configured to emit.jspaths in built output while
allowing source files to use real.tsextensions:allowImportingTsExtensions: truerewriteRelativeImportExtensions: true
All 72 source files have been mechanically updated: every relative
import that previously saidfrom "./foo.js"now says
from "./foo.ts". The compileddist/output still emits the.js
extension, so consumers see no change.Breaking change: the published packages now declare
engines.node: ">=24". Node 22 is no longer supported.CI: the
tests.ymlworkflow bumps from Node 22 to Node 24. Smoke
workflows that setnode-version: 22are left alone — they are
fixtures exercising specific Node versions viaactions/setup-node,
not our project's runtime.
Patch Changes
-
c20a05b: perf(cli): parallelize the startup git calls
The first thing
agent-ci rundoes is ask git for several pieces of
information: the current branch, the head commit SHA, the changed
files, the remote slug, and (when the tree is dirty) an ephemeral
commit that captures the working-tree state. Each call shelled out to
execSync, blocking the event loop for ~50–200 ms.This change converts each of those helpers to use
execFilevia
promisify, so they return promises.handleWorkflowthen runs them
concurrently withPromise.allinstead of one at a time.Functions converted:
getFirstRemoteUrlandresolveRepoSluginconfig.tscomputeDirtyShainrunner/dirty-sha.tsgetChangedFilesinworkflow/workflow-parser.tsresolveHeadSha,resolveBaseSha, andpersistRunResultin
commands/run.ts
Switching from
execSync(command-string)toexecFile("git", [args])
also removes a shell escaping step on every call — args are passed as
an array, not a single string.Refs #334.
-
50933a6: chore: remove unused runtime dependencies
Three runtime dependencies were declared in
package.jsonfiles but
never imported by any source file in the package:log-updatefrom@redwoodjs/agent-ci(the diff-renderer module
replaced it long ago; only stale code comments remain).jsonc-parserfromdtu-github-actions.yamlfrom@redwoodjs/ts-runner(theclipackage still depends
onyaml; this only drops the unused declaration ints-runner).
Smaller
node_modules, smaller published packages, and one fewer
thing to keep up to date when the upstream releases a new version.
No runtime behaviour change. -
4b07e75: refactor(workflow-parser): split the GitHub Actions expression evaluator
Collapses the eight-parameter context that
resolveExprAtom/
evaluateExprValuewere threading through every recursive call into a single
ExprContextobject, extracts each built-in function (hashFiles,fromJSON,
toJSON,format,contains,startsWith,endsWith,join) into its own
handler, and moves context-variable lookups (runner.*,github.*,matrix.*,
secrets.*,vars.*,inputs.*,steps.*,needs.*,env.*) into
resolveContextRef.expandExpressions's public positional signature is
unchanged.No behavioral changes.
-
24387c7: perf(cli): lazy-load command modules so light commands skip the heavy dependency graph
Extracts the
run,retry/abort, andcleancommands into separate modules
loaded via dynamicimport()fromcli.ts. The dispatcher now only loads what
the invoked command actually needs.Measured impact on
agent-ci --help:- Cold start: 240 ms → 20 ms
- Peak RSS: 88 MB → 42 MB
--helpand unknown commands no longer load dockerode, @grpc/grpc-js,
protobufjs, ssh2, the runner graph, or the workflow parser. Behavior of every
command is unchanged;--help/-hnow exits 0 (previously 1, which was a
quirk of falling through the dispatch chain).Refs #334.
-
d0a8495: refactor(local-job): extract three helpers out of
executeLocalJobexecuteLocalJobhad grown to ~860 lines and scored 73 on the
cognitive-complexity metric — the highest in theclipackage after
the previous round of refactors. Three self-contained blocks of code
inside it have been moved into module-scope helpers:pullContainerImageWithProgress(docker, image, store, containerName)
— the ~100-line Docker pull with per-layer download / extract
progress reporting (direct-container mode).seedRunnerBinaryToHost(docker, hostRunnerSeedDir)— the one-time
extraction of the actions-runner binary from the seed image
(direct-container mode).waitForContainerExit(container, waitPromise, timeoutMs)— the
promise-race that force-stops the container if the runner does not
exit within the timeout.
executeLocalJobis now ~715 lines, cognitive 56. No behaviour
change; the full local smoke suite passes. -
2f2af0d: refactor(local-job): lift the timeline-sync closure to module scope
executeLocalJobhad a ~190-lineupdateStoreFromTimelineclosure
that readtimeline.jsonplus the paused-signal file every 100ms and
updated the RunStateStore. The closure captured six mutablelet
variables defined just above it; fallow's previous report flagged it
as the biggest remaining complexity hotspot (cognitive 70).This change pulls the closure to module scope as two helpers:
syncTimelineToStore(state, ctx)— drives one poll tick. Cognitive
score 22.buildStepsFromTimeline(steps, state)— folds the raw timeline
records into theStepState[]shape the renderer expects. Cognitive
score 45.
Both take an explicit
TimelineSyncStateobject that the polling loop
mutates between ticks, plus a read-onlyTimelineSyncContextwith the
paths, store reference, andonNewPausecallback.Also drops
padW/totalStepsfrom the old closure — they were
computed but never used (legacy padding logic).No behaviour change; the full local smoke suite passes 45/45.
-
6b7802b: chore: relax published
engines.nodeback to>=22#351 bumped the published packages'
engines.nodeto>=24along
with the development-side switch to Node's native TypeScript support.
End users never run our source files, only the compiled
dist/cli.js. That compiled output targets ES2020 and only uses APIs
available on Node 22 (the long-term support release), so the
published requirement was stricter than it needed to be.This change:
- Sets
engines.nodeto>=22in@redwoodjs/agent-ciand
dtu-github-actions. End users on Node 22 stop seeing the
"unsupported engine" warning. - Adds
engines.node: ">=24"to the repo-rootpackage.jsonso
contributors keep getting an explicit signal that the development
scripts (which run.tsfiles directly through Node's native
type-stripping) need Node 24.
No code change.
- Sets
-
8d92c73: refactor(cli/run): split
runCmdandhandleWorkflowinto focused helperspackages/cli/src/commands/run.tshoused two very long orchestrator
functions. Static analysis (fallow health) scored them as the two
highest-complexity functions in the cli package:runCmd— cognitive 91, ~228 lineshandleWorkflow— cognitive 136, ~717 lines
They mixed argument parsing, workflow discovery, matrix expansion,
resource classification, scheduling, wave execution, and final reporting
in a single body, which made each one hard to follow and hard to change.This change pulls clearly bounded steps out into top-level helpers
without changing any observable behaviour:parseRunArgs,parseJobsFlag,parseVarFlag,resolveGithubTokenFlag,
discoverRelevantWorkflows,resolveWorkflowArgPath,finalizeRun—
carved out ofrunCmd.expandJobs,classifyJobsResources,runWaveJobs— carved out of
handleWorkflow. TheExpandedJobtype is lifted to module scope so
the new helpers can take it.
New scores (fallow health):
runCmd: cognitive 9 (was 91)handleWorkflow: cognitive 61 (was 136)parseRunArgs: cognitive 26 (new, replaces the inline arg loop)
No runtime behaviour change; full smoke suite passes.
-
a0d3bb0: chore: unexport helpers that were never imported externally
log-prune.tsandgenerators.tshad six identifiers markedexport
that no other file actually imported:DEFAULT_RETAIN_DAYS,DEFAULT_RETAIN_RUNS,DEFAULT_THROTTLE_MS
(used only insidelog-prune.ts)toContextData,toTemplateTokenMapping
(used only insidegenerators.ts)toContainerTemplateToken
(not used anywhere — wholly dead, removed)
Tightens the public surface so callers can't accidentally rely on
internal helpers, and gets a step closer to a clean dead-code report.
No runtime behaviour change.