setup

package
v0.92.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 17, 2026 License: MIT Imports: 1 Imported by: 0

README

Setup Action

This action copies workflow script files to the agent environment.

Description

This action runs in all workflow jobs to provide scripts that can be used instead of being inlined in the workflow. This includes scripts for activation jobs, agent jobs, and safe-output jobs.

The action copies runtime .cjs JavaScript files (excluding tests) from the js/ directory and .sh shell scripts from the sh/ directory.

All files are copied to the destination directory (default: ${{ runner.temp }}/gh-aw/actions). These files are generated by running make actions-build and are committed to the repository.

Usage

- name: Setup Scripts
  uses: ./actions/setup
  with:
    # Destination directory for script files
    # Default: ${{ runner.temp }}/gh-aw/actions
    destination: ${{ runner.temp }}/gh-aw/actions

Inputs

destination

Optional Destination directory for script files.

Default: ${{ runner.temp }}/gh-aw/actions

Outputs

files-copied

The number of runtime JavaScript, JSON, and shell files copied to the destination directory.

Example

steps:
  - uses: actions/checkout@v7
    with:
      sparse-checkout: |
        actions
  
  - name: Setup Scripts
    uses: ./actions/setup
    with:
      destination: ${{ runner.temp }}/gh-aw/actions

Files Included

This action copies files from actions/setup/, including:

JavaScript Files
  • Activation job scripts (check_stop_time, check_skip_if_match, check_command_position, etc.)
  • Agent job scripts (compute_text, create_issue, create_pull_request, etc.)
  • Safe output scripts (safe_outputs_, safe_inputs_, messages, etc.)
  • Prompt rendering scripts (create_prompt.cjs, interpolate_prompt.cjs, etc.)
  • Utility scripts (sanitize_, validate_, generate_*, etc.)
Shell Scripts (7 files from sh/)
  • create_gh_aw_tmp_dir.sh - Creates temporary directory structure
  • start_mcp_scripts_server.sh - Starts MCP Scripts HTTP server
  • print_prompt_summary.sh - Prints prompt summary to logs
  • generate_git_patch.sh - Generates git patches
  • create_cache_memory_dir.sh - Creates cache-memory directory
  • validate_multi_secret.sh - Validates that at least one secret from a list is configured

All files are copied from the committed js/ and sh/ directories which contain the source of truth for all JavaScript and shell scripts.

Development

Structured issue reports

All JavaScript GitHub issue creators publish through js/issue_report.cjs. createReportIssue(client, parameters, report?) renders the report AST before calling the supplied authenticated client's issue API. Existing issue Markdown is imported when no document is supplied. GraphQL work-queue creation uses the same renderIssueParameters boundary, as do staged safe-output previews. Linear uses the Markdown renderer. Jira uses text-preserving normalization before converting its literal description to ADF, without replacing ordinary language characters with visually similar Latin letters.

js/report_ast.cjs defines the typed inline and block nodes, normalization, and GitHub Markdown renderer. The renderer owns escaping, HTTPS link validation, heading levels, balanced details, code fences, and whitespace. It rejects raw HTML/Markdown nodes and redacts diagnostic secrets before choosing delimiters.

js/failure_report.cjs builds reports from md/agent_failure_issue.md. js/report_markdown.cjs imports the runtime template dialect: headings, paragraphs, emphasis, links, images, bare HTTPS URLs, code, lists, task lists, tables, quotes, alerts, separators, and details. Link destinations retain balanced parentheses, and image sources use the same HTTPS validation as links. Source paragraph newlines and explicit Markdown hard breaks use typed break nodes; newlines in scalar metadata still normalize to spaces. Templates are parsed before scalar metadata is substituted. Diagnostic fragments enter through explicit block fields, with headings below the report sections; unsupported HTML remains literal text. New programmatic report content should use AST nodes rather than concatenated Markdown. Empty optional blocks are omitted and rendering is deterministic. Complete fragments are redacted before tokenization, and URL-domain policies apply to fully normalized content.

js/report_footer.cjs builds the footer from the shared attribution template and model/cost metadata. Attribution, expiration, provenance, failure-match markers, and the detection preamble are rendered with the document, not appended afterward. Marker names and fields are validated; marker values cannot close an HTML comment or inject another metadata field. Ordinary double hyphens in identifiers remain unchanged. Unknown placeholders in user-configured footer templates remain literal; internal templates retain strict missing-field validation. Expiration remains a checked task-list item so existing cleanup and deduplication readers continue to work.

The issue publication importer explicitly enables typed metadata comments to preserve grouping, execution provenance, managed islands, and work-queue IDs. Diagnostic imports do not enable them. JSON metadata is serialized without HTML delimiters while preserving decoded values. Configured mentions use explicit mention nodes after the existing safe-output allowlist and budget checks; other text cannot create notifications. Body limits apply after rendering, including escaping and attribution. A repository-wide regression guards against direct REST issue-creation calls outside the shared publisher.

Special syntax has semantic nodes rather than interpolated strings: closing_reference records the closing action, issue number, optional owner/repo, and an explicit enabled flag. Disabled references render an escaped #, including in PR fallback issues; scalar text never becomes an active closing directive. structured_data accepts JSON values and renders a safely fenced JSON block. xml_marker holds a validated name, scalar value, and optional key/value fields; json_marker holds an actual data object, not serialized JSON. Footer provenance uses the same XML-marker node and renderer. Structured data preserves entity-looking strings, redacts secrets, and rejects cycles, getters, non-finite numbers, and other values JSON would silently drop or coerce.

JSONL runtime helpers

Use js/jsonl_helpers.cjs instead of splitting files or maintaining chunk buffers:

const fs = require("node:fs");
const { readJsonlFile, streamJsonl } = require("./jsonl_helpers.cjs");

for (const record of readJsonlFile(filePath)) {
  consume(record);
}

for await (const record of streamJsonl(fs.createReadStream(filePath))) {
  await consume(record);
}

Both iterators are lazy, retain at most the current line and input chunk, and close their input on early termination. Multi-megabyte lines, split UTF-8 characters, CRLF, and a final line without a newline are supported. Blank and malformed lines are skipped; obviously non-JSON lines bypass JSON.parse. All JSON values are supported, including null, false, and 0.

iterateJsonl(textOrLines, options) handles existing text or complete-line iterables. All JSONL iterators accept lineFilter(line, lineNumber), lineTransform(line, lineNumber), optional maxLineLength (UTF-16 code units, unlimited by default), and onError(error, lineNumber). Errors have sanitized messages and physical, one-based line numbers. Filter, callback, and I/O failures propagate. The length limit rejects oversized records after framing; memory remains proportional to the largest line. The filter receives trimmed text before decoding. The transform runs afterward on trimmed text, allowing timestamp prefixes or keyed framing to be removed without changing the event's original rawLine.

For an exact top-level field/value search, pass fieldFilter: { field: "type", value: "wanted" }. All value/event iterators and JsonlParser support this option. A fast string search skips records that cannot match before JSON.parse; decoded candidates must have their own matching field. Values may be strings, finite numbers, booleans, or null. Escaped keys/values and alternate numeric spellings still match correctly. Filtering occurs after lineTransform, and filtered records are omitted, not validated. Do not use this option when every record must be validated or retained for redaction.

let found = false;
for (const record of readJsonlFile(filePath, {
  fieldFilter: { field: "type", value: "wanted" },
})) {
  found = true;
  break; // No later records are decoded; the file closes immediately.
}

Use the same option with iterateJsonl(text) or streamJsonl(chunks). String inputs also short-circuit before line scanning when no match is possible.

Pass schema to validate decoded records using the lightweight memory schema subset: type, enum, required, properties, additionalProperties: false, items, oneOf, and anyOf. Unsupported schemas fail before reading input. Schemas are prepared once per iterator or persistent parser; numeric enums also check raw numeric tokens for rounding, without constraining unrelated numbers. Schema failures are invalid events with reason "schema" and validationError: { path, message }. Value iterators skip them unless strict: true is set. Filters still omit records before validation. For example: readJsonlFile(filePath, { schema: { type: "object" }, strict: true }).

Set fatalUTF8: true on byte-backed file, streaming, or persistent parsers to report malformed UTF-8 as invalid events with reason "encoding", preserving physical line numbers. Set jsonWhitespaceOnly: true to reject non-JSON framing whitespace such as BOM and NBSP. Memory schema validation enables both options; the default tolerant log parsing behavior is unchanged.

For redaction or diagnostics that must retain rejected input, use iterateJsonlEvents(textOrLines), readJsonlFileEvents(filePath), or streamJsonlEvents(chunks). Each event has type ("json" or "invalid"), rawLine (including its original LF/CRLF terminator, if present), and lineNumber. JSON events also have value; invalid events have a sanitized error and a reason ("syntax", "too-long", "blank", "schema", or "encoding"). Blank lines are emitted but do not invoke onError. No synthetic empty event follows a final newline. Without a filter, concatenating rawLine reproduces the original text exactly. Raw lines and schema paths are untrusted and may contain secrets; redact them before logging.

const { iterateJsonlEvents, readJsonlFileEvents } = require("./jsonl_helpers.cjs");

for (const event of iterateJsonlEvents(text)) {
  writeRedacted(event.type === "json" ? redactJson(event.value) : redactText(event.rawLine));
  if (shouldStop()) break;
}

for (const event of readJsonlFileEvents(filePath)) {
  if (isWanted(event)) {
    consume(event);
    break; // Stops decoding and closes the file immediately.
  }
}

The event iterators support break, return, and explicit iterator .return(); they do not decode later records, even in an already-read chunk. Async iterators also close their upstream source. Value-only iterators accept { strict: true } to throw on any invalid record, including blank lines, instead of skipping it. Create one iterator per input; do not restart a parser for each manually split line. There is no exported standalone record decoder.

Ledger, work-queue, and repo-memory JSONL readers use these shared iterators. File-backed usage and audit ledgers stream directly from disk. Queue readers retain bounded buffers where transport-wide UTF-8 validation is required and apply parseStrictJSON to each original rawLine, preserving duplicate-key, numeric, Unicode, and resource checks. Shared framing does not make corrupted queue history skippable or replace canonical-byte and hash verification.

Callback-driven protocols use one persistent JsonlParser per stream:

const { JsonlParser } = require("./jsonl_helpers.cjs");
const parser = new JsonlParser();
source.on("data", chunk => {
  for (const event of parser.push(chunk)) consumeEvent(event);
});
source.on("end", () => {
  for (const event of parser.finish()) consumeEvent(event);
});

push and finish return lazy event iterators. Consume each iterator completely before feeding more input; stopping an iterator is appropriate only when abandoning that stream. Invalid protocol events can be rejected using event.error. JsonlParser, streamJsonlEvents, and streamJsonl also accept an opt-in maxPendingRecordLength (positive safe integer). It counts raw UTF-16 code units, including LF/CRLF, per record, not total stream size or UTF-8 bytes. Framing checks the bound before retaining fragments or joining a complete record, even when a single chunk contains the whole record. Exceeding it releases pending fragments and throws a sanitized, terminal RangeError; abandon the parser and terminate the source rather than expecting an invalid event or calling finish afterward. The default remains unlimited, and maxLineLength retains its separate after-framing behavior. The Agy harness and Pi sub-agent runner explicitly use 16,777,216 UTF-16 code units per raw record and terminate children on overflow, while allowing legitimate multi-megabyte records. Custom repair or framing formats can use iterateLines(text), readLines(filePath), streamLines(chunks), or LineFramer.push(chunk) / finish() without duplicating line buffering. parseJsonlContent remains an eager compatibility wrapper for callers that require an array; prefer iterators when results need not be retained.

The js/ and sh/ directories contain the source of truth for all JavaScript and shell script files. These files are manually edited and committed to the repository.

To update JavaScript files:

# Edit files in actions/setup/js/
# Format the JavaScript files
make fmt-cjs

# Lint the JavaScript files  
make lint-cjs

# Commit the changes
git add actions/setup/js/
git commit -m "Update JavaScript files"

To update shell scripts:

# Edit files in actions/setup/sh/
# Commit the changes
git add actions/setup/sh/
git commit -m "Update shell scripts"

Note: JavaScript and shell files are NOT embedded in the binary. They are copied at runtime by setup.sh from actions/setup/js/ and actions/setup/sh/ to ${{ runner.temp }}/gh-aw/actions where workflows can access them.

The separate MCP Scripts and safe-outputs directories use the explicit MCP_SCRIPTS_FILES and SAFE_OUTPUTS_FILES lists in setup.sh. Update these lists when adding or removing their runtime modules, including transitive local dependencies. Check deployment completeness with:

cd actions/setup/js
npx vitest run setup_sh_file_lists.test.cjs
MCP gateway step summaries

Gateway summaries share a 1000 KiB UTF-8 byte budget, including any existing content in the step summary file, below GitHub Actions' 1024 KiB limit. Oversized sections become bounded, collapsed diagnostic previews with an explicit truncation notice. Each section receives a share of the remaining budget so large logs do not crowd out rate-limit, steering, or filtering diagnostics. Complete redacted gateway logs remain under mcp-logs/ in the existing agent artifact.

Testing Locally

You can test this action locally using the provided test script:

./test-setup-local.sh

This script will:

  1. Check if js/ directory exists (runs make actions-build if needed)
  2. Run setup.sh with test configuration
  3. Verify all files are copied correctly

Documentation

Index

Constants

This section is empty.

Variables

View Source
var SessionParserSources embed.FS

SessionParserSources contains the runtime parsers and their transitive dependencies, not test fixtures. The CLI uses the same sources as Actions.

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL