Replace the 20-line tail (with "Last output:" label and indentation)
with the full content of the per-step log file already captured at
failedStepLogPath. Falls back to lastOutputLines when no log file
exists (e.g. container crash).
Adds reporter.test.ts to prove the behaviour, and an end-to-end check
in tests.yml that runs the retry-proof workflow and asserts the step
output appears in stdout.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move website from website/ to apps/website/ (update pnpm workspace)
- Remove logo icon from navbar, keep AGENT-CI text
- Configure domain routes for agent-ci.dev in wrangler.jsonc
- Replace tabs with stacked tables in compatibility matrix
- Expand all ⚠️ and ❌ notes with reasons and details
- Update compatibility.md to match website content
- Fix useContext SSR error by removing motion/react, using CSS animations
- Add img-src CSP header for pbs.twimg.com (Twitter profile images)
- Remove npx run --all command from hero, rename button to Quick start
- Remove decorative border elements from hero section
- Update footer "Built by" link to rwsdk.com
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Limit Docker API URL rewrites to loopback hosts, keep alias-based defaults unless an explicit bridge gateway override is configured, and update docs/tests to match behavior.
On Linux, host.docker.internal doesn't work by default (only available
since Docker 20.10+ and requires explicit configuration). This change:
- Detects macOS vs Linux and returns appropriate host IP
- Uses 172.17.0.1 (docker bridge gateway) on Linux host
- Uses host.docker.internal on macOS
- Adds containerUrl to ephemeral DTU for container-to-host communication
- Adds ExtraHosts mapping for containers to resolve host.docker.internal
Fixes connectivity issues when running agent-ci on Linux hosts.
Ensures the commands work even when the package isn't installed as a
local devDependency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add "(in Docker)" clarification to SKILL.md
- Explain --all flag matches on triggers like GitHub
- Add --no-matrix tip for collapsing matrix jobs locally
- Use --quiet flag in CLAUDE.md snippet
- Add "CI was green before you started" instruction for agents
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Improve npm and AI agent discoverability by filling in package.json
keywords/description, creating a SKILL.md for node_modules scanning,
and adding a ready-to-paste CLAUDE.md snippet to the README.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Parse --no-matrix as a boolean flag in the run command. Thread noMatrix
through runWorkflows and handleWorkflow. When active, use a new
collapseMatrixToSingle helper (exported from workflow-parser.ts) to
produce one job with the first value of each matrix key, __job_total='1',
and __job_index='0', so strategy.job-total expressions resolve correctly
without parser changes. Document the flag in printUsage.
Covers: collapseMatrixToSingle produces exactly one job, uses first value
of each matrix key, sets __job_total='1' and __job_index='0', handles
multi-key matrices and edge cases (degenerate single-combo, empty value
list, numeric values). Also guards that expandMatrixCombinations (default
path) is unaffected and produces the full cartesian product without
injecting __job_total or __job_index.
@actions/workflow-parser imports .json files without `with { type: "json" }`,
which Node 22 rejects. This adds a custom ESM loader hook that transparently
patches the missing attribute at runtime.
Closes#67
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
execa was in devDependencies but imported in production code,
causing ERR_MODULE_NOT_FOUND when running via npx. Replaced with
Node's built-in child_process.exec and removed execa entirely.
When a runner-specific job was seeded, it was stored in both state.jobs
(generic pool) and state.runnerJobs (runner-targeted). A runner polling
before its own job was seeded could fall back to state.jobs and steal
another runner's job, leaving the original runner spinning indefinitely.
Fix: runner-targeted jobs now go only into state.runnerJobs. The generic
pool is reserved for jobs without runner affinity.
Adds three tests covering the race condition, concurrent stress with
8 runners, and the job-theft scenario.
Closes#47
The runner's FinalizeJob deletes _temp/_runner_file_commands/ inside the
container before exit, making files unreachable from the host.
Solution: inject a synthetic 'Capture outputs' step (runs with if:always())
that reads all set_output_* files and echoes them as ::agent-ci-output::key=value.
The DTU parses these prefixed lines and persists them to outputs.json in the
runner's log directory. On job completion, local-job.ts reads outputs.json and
attaches the outputs to the JobResult.
Pipeline verified end-to-end — all 8 smoke tests pass:
- Cross-job outputs (setup-outputs → consume-outputs) ✅
- Job-level if:always() ✅
- Matrix shards with fail-fast:false ✅
- Artifacts, services, env vars ✅
All 279 unit tests pass.
- Fix extractStepOutputs path: _temp/_runner_file_commands/ (not root)
- DTU outputs endpoint now captures and persists outputs.json
- local-job.ts reads outputs.json from log dir instead of work dir
- Add smoke test jobs for cross-job outputs and if:always()
All 279 tests pass.
#54 - Job-level if conditions:
- shouldSkipJob() evaluates if: conditions before dispatching
- Tracks upstream job results (success/failure/skipped)
- Creates synthetic skipped results for skipped jobs
- Default behavior: skip if any upstream dependency failed
#55 - Respect fail-fast setting:
- Replaces unconditional wave abort with parseFailFast check
- Only aborts if not all jobs in wave have fail-fast: false
- Logs when continuing despite failures
All 279 tests pass.
- parseWorkflowSteps now accepts needsContext parameter
- All expandExpressions calls in step parsing thread needsContext
- cli.ts wave loop accumulates job outputs and builds needsContext
for downstream jobs
- Step names now use raw YAML value for expression preservation
2 new tests, all 279 pass.
resolveJobOutputs() resolves job output templates (e.g.
${{ steps.check.outputs.skip }}) against the flat step outputs
captured by extractStepOutputs().
6 new tests, all 277 pass.