Commit Graph

23 Commits

Author SHA1 Message Date
Peter Pistorius c8da13a8dc feat(cli): add var-file workflow vars (#361) 2026-05-19 14:38:33 +02:00
Will Roever 6a26caefa6 feat(workflow): support env.* context references in expressions (#320)
* feat(workflow): support expansion of env context references in expressions

`${{ env.* }}` references in workflow expressions silently resolved to empty
string because `resolveExprAtom` had no `env.` handler and no env context was
threaded through the evaluator. The fix adds initial support for expanding these
references in `run:` scripts, `with:` inputs, `name:`, and `env:` value
expressions — matching GitHub Actions behavior. `if:` conditions remain
unsupported (noted in `compatibility.md`).

* chore(smoke): add smoke-env-context.yml as proof for env.* row

Adds a smoke workflow that exercises ${{ env.* }} expansion in `run:`
bodies, in another step's `env:` value, in `with:` inputs (the original
Rails CI bug surface), and verifies the unknown-key → empty-string
contract. Also wires it as the `proof` reference on the env.* row in
compatibility.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Peter Pistorius <peter.pistorius@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:10:17 +02:00
Simon 44595b134e feat(cli): surface degraded local runs for resource mismatches (#230)
* feat(cli): surface degraded local runs for resource mismatches

Add resource fidelity classification that compares local host resources
against workflow-declared runner/resource hints. When the local machine
is smaller than what the workflow requests, jobs are marked as degraded
and a warning is shown before execution starts.

Features:
- Parse runs-on labels and NODE_OPTIONS from workflows
- Classify jobs as faithful or degraded based on CPU/memory hints
- Show [degraded] tag and actionable warnings in CLI output
- Add smoke test for degraded classification
- Update documentation with degraded mode guidance

Complements PR #226 which adds memory-aware concurrency limiting.
Together they replace the approach in closed PR #78.

* refactor(cli): use runner specs instead of NODE_OPTIONS for resource classification

Replace NODE_OPTIONS parsing with GitHub runner label heuristics.
This is more accurate and works for all workloads (not just Node).

Changes:
- Add RUNNER_SPECS mapping for known GitHub runner sizes
- Add parseRunnerSpecs() to look up full {cpu, memory} from labels
- Remove parseNodeMaxOldSpaceMb() and NODE_OPTIONS dependency
- Update tests to use runner specs
- Simplify smoke test fixture

Runner specs used:
- ubuntu-latest: 2 CPU, 7GB RAM
- ubuntu-latest-4-cores: 4 CPU, 16GB RAM
- ubuntu-latest-8-cores: 8 CPU, 32GB RAM
- ubuntu-latest-16-cores: 16 CPU, 64GB RAM

* feat(cli): warn when using unknown runner labels

When a workflow uses an unknown runner label (e.g., 'self-hosted' or custom
labels not in RUNNER_SPECS), the job is now marked as degraded with a
warning that explains we're assuming local host capacity.

This makes the behavior transparent - users know we're making an assumption
about the runner size rather than silently defaulting to faithful mode.

* Address PR review comments: remove smoke tests, resource warnings, and writeStdoutLine refactor

* Remove remote Docker daemon suggestion from degraded resource warnings

* chore(compat): add resource-mismatch smoke and document degraded mode

- Add smoke-resource-mismatch.yml fixture that uses ubuntu-latest-999-cores
  to deterministically trigger the degraded classification on any host.
- Extend the runs-on row in compatibility.json with a sentence describing
  the degraded warning and reference the smoke as proof.
- Regenerate compatibility.md.
- Add changeset.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(classifier): only flag unknown labels for the ubuntu family

The "unknown runner label" reason fired for any label missing from
RUNNER_SPECS, including macos-* / windows-* / self-hosted — labels that
runs-on-compat already handles and that the resource classifier has no
useful opinion on. Restrict the warning to labels that look like a
hosted ubuntu variant (`ubuntu` or `ubuntu-*`), which is the family
RUNNER_SPECS actually covers; this still catches drift when GitHub
adds a new ubuntu label without us noticing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(smoke): de-flake bun smoke by pre-fetching the binary

The smoke depended on oven-sh/setup-bun@v2 pulling bun-linux-aarch64.zip
from github.com/oven-sh/bun/releases inside the nested runner. The
upstream action has no per-request timeout or retry, so a stalled CDN
socket presented as a hung step with one log line ("Downloading a new
version of Bun: …") and nothing else — pure flake, no signal about
agent-ci.

Pre-fetch the binary on the outer host with curl --retry, ship it into
the inner workspace as a fixture, and replace the setup-bun call in the
inner workflow with two narrower steps that exercise the actual #212
failure modes: an actions/cache@v4 probe against a randomized `bun-…`
key (must miss — guards against the virtualCachePatterns substring
fake-hit) and a manual `mkdir -p $HOME/.bun/bin` install (exercises the
bind-mount permissions path).

Local run: 16s, deterministic.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Peter Pistorius <peter.pistorius@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:10:03 +02:00
Peter Pistorius fdec27e537 docs(compat): split the overloaded rows surfaced by the #296 audit (#305)
Each overloaded row becomes one row per documented feature (or a tighter
note when the sub-features behave identically). No behaviour changes.

  * github.*        split into sha / repository family / everything-else
  * runner.*        new row for unsupported siblings
  * contains etc.   three rows, one per function
  * success family  downgraded partial (cancelled() always false locally)
  * on (other)      note enumerates ~20 events

Closes the "overloaded row" bucket on #296.

Refs #296.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 10:39:28 +02:00
Peter Pistorius 5a23a5a22d docs(compat): fill in 15 previously-absent rows from the #296 spec audit (#304)
Adds rows for features GitHub Actions documents that our compat table
said nothing about. Each status was picked per code inspection of the
existing parser / runner paths — no behaviour changes.

Closes the "missing rows" bucket on #296.

Refs #296.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 10:38:58 +02:00
Peter Pistorius 044de23532 fix(runner): forward --env/--label from container.options into createContainer (#303)
The YAML parser extracted `jobs.<id>.container.options` into job.container
but the docker createContainer call never consumed it, so `options: --env
FOO=bar` silently produced a container without FOO.

parseContainerOptions now pulls --env/-e and --label/-l out of the options
string and merges them into the container's Env array and Labels map. All
other Docker flags in options: are still ignored by design — --privileged,
--user, --network, --cap-add, --workdir tend to clash with agent-ci's own
container orchestration, and silently dropping them is safer than a partial
honoring that breaks the runner's invariants. Documented in the
compatibility.json note for jobs.<id>.container.

Also updated two nearby notes while running through #296:

  * actions/cache — documents the lack of ref-based isolation (branches
    share cache keys locally, unlike GitHub's per-ref scoping)
  * GITHUB_TOKEN — documents that OIDC id-token issuance is not wired up,
    so permissions: id-token: write → federated cloud auth does not work

Refs #296.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 10:38:36 +02:00
Peter Pistorius ab410c79c9 fix(workflow): toJSON pretty-print + empty-string numeric coercion (#302)
Two small expression-engine fixes surfaced by extending smoke-expressions
with assertions for #296's "questionable claim" rows:

1. toJSON now emits 2-space-indented JSON (was compact), so hashFiles
   keys that hash a toJSON(x) match GitHub. Parses rawValue first so
   toJSON(fromJSON(x)) round-trips cleanly.

2. compareValues() no longer bails out of the numeric path when either
   side is empty. `''`, `null`, and numeric strings all coerce to
   numbers per the spec; non-numeric strings become NaN (string compare
   path, always false).

Five new assertions (contains-on-array, toJSON pretty-print, coercion,
hashFiles multi-pattern, hashFiles negation) all pass. hashFiles
multi-pattern and negation were never broken — cleared off #296 with
proof rather than a fix.

Refs #296.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 10:38:12 +02:00
Peter Pistorius f44620bf35 fix(workflow): hashFiles + steps.*.outputs.* — two small correctness fixes (#300)
* fix(workflow): hashFiles descends into dotted directories

findFiles was skipping any directory starting with `.`, so a pattern
like hashFiles('.github/workflows/*.yml') never matched a file and
returned the 40-zero placeholder. Skip only node_modules now.

The smoke assertion is tightened back to 64 chars (SHA-256) since the
real digest now appears.

Closes #294.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(workflow): resolve steps.*.outputs.* to empty at parse time

The parser was returning a sentinel so that `${{ steps.X.outputs.Y }}`
expressions would be preserved verbatim for the runner to evaluate at
runtime. The runner does not re-evaluate expressions inside run-script
bodies, so the literal `${{ }}` reached bash as "bad substitution".

Per the long-standing compatibility contract, these expressions now
resolve to an empty string at parse time. Cross-job values still work
through needs.*.outputs.*.

Closes #295.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 10:37:41 +02:00
Peter Pistorius 78e3e01266 fix(workflow): honor shell: for non-bash via parse-time heredoc wrap (#299)
The runner executes every run: step with bash regardless of inputs.shell,
so setting shell: sh / python / pwsh had no effect. Wrap the expanded
script at parse time — `<interpreter> <flags> <<'EOF' ... EOF` — so the
requested shell actually runs the user's code. Workflow, job, and step
scopes compose via the existing resolveStepRunDefault helper.

Adds smoke-shell-defaults.yml (removed in an earlier bug-filing cut)
covering all three scopes with a BASH_VERSION assertion.

Closes #293.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 10:36:30 +02:00
Peter Pistorius e2fe5761ba feat(compat): JSON source of truth + fill gaps + fix defaults.run.working-directory (#291)
* feat(compat): make compatibility.json the source of truth

Flip the compatibility matrix so packages/cli/compatibility.json is
authoritative. scripts/gen-compatibility-md.mjs renders the .md from it,
pnpm check runs a drift check, and the website imports the JSON directly
and renders inline markdown in keys/notes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test: add compat smoke coverage for secrets, working-dir defaults, runner image

Fill three audit gaps identified against packages/cli/compatibility.json:

- smoke-secrets-env-file: secrets resolved from .env.agent-ci and from
  the shell environment fallback
- smoke-defaults-workdir: workflow- and job-level
  defaults.run.working-directory plus a step-level override
- smoke-runner-image: .github/agent-ci.Dockerfile is picked up and the
  resulting image is used at job start

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(workflow): propagate defaults.run.working-directory to steps

Parse defaults.run.working-directory at workflow and job level and merge
it into each run-step's inputs with step > job > workflow precedence.
Step-level working-directory already worked; the defaults blocks were
silently ignored.

Closes #290.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(compat): add proof field to compatibility.json rows

Every `supported`/`partial` row now lists the smoke workflows that
exercise it end-to-end. `pnpm compat:gen`/`compat:check` fails if a
listed path does not resolve, catching renames.

Rows with an empty `proof: []` are the audit gaps tracked in #292.

Refs #292.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(dtu): attach step env per-step so it does not leak to siblings

Step-level env was being aggregated into the job-wide EnvironmentVariables
map (last-wins), so a later step's `env: FOO=x` would override an earlier
step's effective FOO at runtime. Emit step.Env as the mapped step's own
`environment` instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(compat): fill audit gaps #292 — env, expressions, local action

Three smokes covering eight of the ten gaps listed in #292:
- smoke-env-scoping: workflow + job + step `env:` precedence
- smoke-expressions: hashFiles, format, join, runner.arch, type
  literals, startsWith/endsWith
- smoke-local-action: `steps[*].uses: ./.github/actions/...`
  (verified via marker file rather than steps.<id>.outputs.*)

Proof fields updated for every row these smokes cover. hashFiles
downgraded to ⚠️ partial — agent-ci emits SHA-1, GitHub Actions emits
SHA-256 (tracked by #294).

Two gaps remain open as filed issues:
- #293 defaults.run.shell / steps[*].shell not applied
- #295 ${{ steps.<id>.outputs.<name> }} leaks literal text in run
  scripts

Refs #292.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 08:47:20 +02:00
Peter Pistorius 12220befc4 Run macos-* jobs in real macOS VMs via tart (#275)
* feat(cli): run macos-* jobs in real macOS VMs via tart

When the host is darwin/arm64 with tart + sshpass installed, jobs
targeting runs-on: macos-* boot an ephemeral cirruslabs macOS VM,
rsync the macOS actions-runner binary in, and connect it to the
in-process DTU via the host bridge.

- New runner/macos-vm/ module (tart wrapper, image mapping, host
  capability probe, runner binary fetch/cache, semaphore, job driver).
- cli.ts routes macOS jobs to the VM executor when the host supports
  it; otherwise falls through to the existing skip-with-warning path.
- DTU generators.ts accepts runnerWorkDir/runnerOs/runnerArch so the
  seed payload reflects where the runner actually materializes _work
  (sibling of run.sh, not a caller-chosen path).
- runner-credentials.ts extracted from local-job.ts so the macOS path
  can reuse the same deterministic .runner/.credentials generation.

Concurrency capped at 2 VMs by default (AGENT_CI_MACOS_VM_CONCURRENCY).
Image override via AGENT_CI_MACOS_VM_IMAGE.

Closes #258.

* feat(cli): say *why* macOS jobs skip on incapable hosts

Before: the skip warning for macos-* jobs on a host that can't run the
VM just pointed at #258 and parroted the pre-Phase-3 line about only
running in a Linux container — which is no longer accurate now that
macOS jobs *can* run locally when the host supports it.

Now: formatUnsupportedOSWarning accepts the HostCapability result and
prints the specific reason + install hint when available — e.g.
'tart not installed' with a brew command, or 'requires Apple Silicon
(got x64)'.

* refactor(cli): deduplicate runs-on classification + warning body

- cli.ts: extract classifyJob(ej) + canRunMacosHere(kind) so the
  skip path and the executor-routing path share one source of truth
  for 'should this job run in the macOS VM?' — the two previously
  duplicated the parseJobRunsOn + classifyRunsOn + capability check.
- runs-on-compat.ts: flatten formatUnsupportedOSWarning to a single
  body array per kind, filter undefined, then uniformly indent —
  drops the optional-hint if-branch and the per-push indent literals.

Pure refactor; all 14 runs-on-compat tests still pass, warning output
is byte-identical across all 4 permutations (macOS with/without
capability, with/without hint, windows).

* docs: document macOS VM runner support

- README: add tart + sshpass to 'Optional' prerequisites and a new
  'macOS jobs' section (image table, env vars, caveats).
- compatibility.md: unstale the three entries that claimed Linux-only
  (jobs.<id>.runs-on, runner.os, runner.arch). runs-on now reads as a
  partial (⚠️) that explains linux/macos/windows separately.

Leaves apps/website/CompatibilityMatrix.tsx alone — it has the same
stale rows but is in an unrelated mid-merge state on this branch.

* chore: oxfmt packages/cli/README.md and compatibility.md
2026-04-18 12:32:35 +02:00
Peter Pistorius ca4610fb95 fix: evaluate boolean operators in workflow expressions (#236)
* fix: support boolean operators and built-in functions in workflow expressions (#224)

The workflow expression evaluator only understood simple variable lookups
and hashFiles(). Expressions like `!github.event.pull_request && format(...)  || 'plan'`
would silently fail, producing wrong values.

Add support for `&&`, `||`, `!`, parentheses, `format()`, `toJSON()`,
and string literals so these expressions evaluate correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* revert: drop MAYBE_SUDO from docker socket chmod

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: add contains, startsWith, endsWith, join, comparison operators, and type literals

Expand the expression evaluator to cover the remaining GitHub Actions
expression features: string search functions, comparison operators
(==, !=, <, >, <=, >=), status functions, and literal types
(true, false, null, numbers).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: update compatibility table for new expression features

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style: fix formatting in compatibility.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 12:09:17 +02:00
Peter Pistorius 9d1c0f4031 fix: format markdown files and auto-format after changeset version (#221)
The release workflow failed because changeset-generated CHANGELOGs weren't
formatted. Fix the existing files and run oxfmt after `changeset version`
so future Version Packages PRs include formatted markdown.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:35:23 +02:00
Peter Pistorius c8c2b6cbcd docs: update compatibility.md to reflect current behavior (#199)
* docs: update compatibility.md to reflect current behavior

- GITHUB_TOKEN: no longer auto-injected, requires --github-token or AGENT_CI_GITHUB_TOKEN
- github.sha: now uses real commit SHA from HEAD, not hardcoded zeros
- secrets: documents env var fallback and --github-token auto-population

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: update github.sha to reflect dirty-tree SHA support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-12 12:32:52 +02:00
Peter Pistorius 66ac2a4b6b test: smoke repro for missing cc in runner image (#207)
* test: add smoke repro for missing cc in runner image

Minimal smoke workflow that calls `command -v cc` and compiles a
trivial C program. Reproduces a cargo/Rust workflow failure where
`linker 'cc' not found` breaks builds under agent-ci-dev because
ghcr.io/actions/actions-runner:latest does not ship build-essential.

CI-only change (no packages/ code modified) — no changeset.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: pluggable runner image via .github/agent-ci.Dockerfile (#208)

agent-ci now discovers a user-provided Dockerfile at
.github/agent-ci.Dockerfile (or .github/agent-ci/Dockerfile for builds
with a COPY context), hashes its contents, builds it locally via
`docker build`, and uses the resulting agent-ci-runner:<hash> tag as
the default runner image. Edits trigger automatic rebuilds; identical
contents reuse the cached image.

This closes the gap where the minimal ghcr.io/actions/actions-runner
image lacks build-essential, python3, and other toolchains that
GitHub's hosted ubuntu-latest VM ships preinstalled. Workflows green
on GitHub but failing locally with `linker 'cc' not found` can now
opt into a richer image by dropping a 5-line Dockerfile into .github/.

Resolution order (highest wins):
  1. per-job `container:` (unchanged)
  2. AGENT_CI_RUNNER_IMAGE env var
  3. .github/agent-ci/Dockerfile (directory form, supports COPY)
  4. .github/agent-ci.Dockerfile (simple form, empty context)
  5. ghcr.io/actions/actions-runner:latest (default)

Also adds an error-hint heuristic: when a step fails with "command not
found" for cc/gcc/make/python3/pkg-config and the user is still on the
default image, the failure summary includes a paste-ready Dockerfile
pointing at the fix. Docs at packages/cli/runner-image.md.

Dogfoods the feature by shipping .github/agent-ci.Dockerfile for this
repo, which makes smoke-cc-compiler.yml (the issue #208 reproduction)
pass end-to-end.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: announce first-run runner image build

Print a one-time stderr notice before `docker build` fires so users
understand why the first run pauses for ~60s. The message lives in
stderr so log-update can't clobber it and stays in scrollback after.

Docs updated to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: clarify that container: runs verbatim, no Dockerfile layering

Spell out explicitly that a job-level container: directive bypasses
.github/agent-ci.Dockerfile entirely — agent-ci does not layer the
Dockerfile on top. This preserves the "same YAML runs locally and on
GitHub" parity promise.

Also document the two recommended ways to combine a custom base
image with agent-ci's extras.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-11 20:12:21 +02:00
Peter Pistorius 1f24fecc14 fix: make GitHub auth opt-in for remote workflow fetching (#183)
* fix: make GitHub auth opt-in for remote reusable workflow fetching

Remove implicit credential resolution (gh auth token / GITHUB_TOKEN fallback)
that could silently send user credentials. Auth is now opt-in via
--github-token CLI flag or AGENT_CI_GITHUB_TOKEN env var.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: add changeset for opt-in GitHub auth

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add --github-token flag and AGENT_CI_GITHUB_TOKEN to docs

Update CLI reference tables, environment variables section, and
compatibility matrix to reflect opt-in GitHub auth for remote
reusable workflows.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: make commit status posting opt-in via --github-token

Gate postCommitStatus() on the githubToken parameter. When no token
is provided, print a warning instead of silently using implicit
gh CLI credentials.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add --commit-status flag to opt in to posting GitHub commit statuses

Commit status posting now requires both --commit-status and
--github-token. Without --commit-status, no warning is printed
and no status is posted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add tests for 403 error hint and public repo fetch without auth

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 11:55:26 +02:00
Peter Pistorius 6b7a95b180 feat: support local composite actions (#169)
* feat: support local composite actions (`uses: ./.github/actions/...`)

Set RepositoryType to "self" for local action references so the runner
resolves them from the workspace instead of trying to download a tarball.
Add defensive guard in actiondownloadinfo to skip local/empty actions.

Closes #162

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: fix formatting in .docs/ files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 17:07:31 +02:00
Peter Pistorius e9c5df5f6f feat: support reusable workflows (local and remote) (#163)
* feat: support local reusable workflows (uses: ./.github/workflows/...)

Inline called workflow jobs into the caller's dependency graph so that
`jobs.<id>.uses` with local refs works end-to-end. Includes dependency
rewiring, smoke tests, runner seed resilience fix, boot-failure log
surfacing, and dev script improvements.

Closes #149

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: update website compatibility matrix for reusable workflows

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add section descriptions to website compatibility matrix

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add descriptions to compatibility matrix legend items

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add 'not planned' status icon to compatibility matrix

Distinguish architectural limitations (concurrency groups, GitHub
secrets) from features that could be implemented in the future.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: support remote reusable workflows (uses: owner/repo/path@ref)

Pre-fetch remote workflow YAML from GitHub Contents API before expansion,
cache SHA refs forever and always re-fetch mutable tag/branch refs. Also
changes missing workflow files from warn+skip to hard failure.

Closes #165

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: split monolithic smoke-tests.yml into discrete workflow files

Each smoke test area now has its own workflow file for isolated failure
visibility: matrix, artifacts/services, cross-job outputs, job conditions,
reusable workflows (local + remote), and binary smoke.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: fix formatting in .docs/ files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: clarify agent-ci-dev.sh is for local development only

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 17:07:13 +02:00
Peter Pistorius bdd269ff10 feat: move website to apps/website, improve content and fix SSR
- 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>
2026-03-27 17:27:26 +11:00
Peter Pistorius 8fadb39584 Fix docs formatting. 2026-03-17 08:13:29 +13:00
Peter Pistorius 9769aac57b Update docs. 2026-03-17 08:10:35 +13:00
Peter Pistorius 275cf2bff6 feat: add workflow compatibility features
- fromJSON()/toJSON() expression functions
- Cross-job outputs: needsContext in expandExpressions, parseJobOutputDefs
- Job-level if: parseJobIf, evaluateJobIf with always/success/failure/==/!=
- strategy.fail-fast: parseFailFast
- extractStepOutputs: reads $GITHUB_OUTPUT files from _runner_file_commands
- outputs field added to JobResult
- Updated compatibility.md

39 new tests, all 271 tests pass.
2026-03-15 07:53:17 +13:00
Peter Pistorius c8dd79f478 chore: move cli and dtu-github-actions into packages/ 2026-03-13 00:07:29 +02:00