@autohq/cli 0.1.371 → 0.1.373

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.
@@ -23492,7 +23492,7 @@ Object.assign(lookup, {
23492
23492
  // package.json
23493
23493
  var package_default = {
23494
23494
  name: "@autohq/cli",
23495
- version: "0.1.371",
23495
+ version: "0.1.373",
23496
23496
  license: "SEE LICENSE IN README.md",
23497
23497
  publishConfig: {
23498
23498
  access: "public"
@@ -25412,10 +25412,15 @@ var AgentModelOpenRouterSchema = external_exports.object({
25412
25412
  models: external_exports.array(external_exports.string().trim().min(1).regex(OPENROUTER_MODEL_SLUG_PATTERN)).min(1).max(3),
25413
25413
  provider: AgentModelOpenRouterProviderPrefsSchema.optional()
25414
25414
  }).strict();
25415
+ var AgentModelFallbackSchema = external_exports.object({
25416
+ provider: ModelApiTokenProviderSchema.optional(),
25417
+ id: external_exports.string().trim().min(1).max(256)
25418
+ }).strict();
25415
25419
  var AgentModelSelectionSchema = external_exports.object({
25416
25420
  provider: ModelApiTokenProviderSchema.optional(),
25417
25421
  id: external_exports.string().trim().min(1).max(256),
25418
- openrouter: AgentModelOpenRouterSchema.optional()
25422
+ openrouter: AgentModelOpenRouterSchema.optional(),
25423
+ fallbacks: external_exports.array(AgentModelFallbackSchema).min(1).max(2).optional()
25419
25424
  }).strict();
25420
25425
  var ResolvedAgentModelSelectionSchema = AgentModelSelectionSchema.extend({
25421
25426
  provider: ModelApiTokenProviderSchema
@@ -25426,7 +25431,12 @@ var ModelRoutingOpenRouterSchema = external_exports.object({
25426
25431
  }).strict();
25427
25432
  var ModelRoutingConfigSchema = external_exports.object({
25428
25433
  primaryModelId: external_exports.string().min(1),
25429
- openrouter: ModelRoutingOpenRouterSchema.optional()
25434
+ openrouter: ModelRoutingOpenRouterSchema.optional(),
25435
+ // Capability 1 — the ordered same-provider fallback chain the gateway
25436
+ // rewrites `body.model` through when the primary exhausts the transient
25437
+ // retry loop. Mutually exclusive with `openrouter` by construction (the
25438
+ // authored fields are mutually exclusive at validation).
25439
+ fallbackModelIds: external_exports.array(external_exports.string().min(1)).min(1).max(2).optional()
25430
25440
  }).strict();
25431
25441
  var InvalidModelSelectionError = class extends Error {
25432
25442
  constructor(message) {
@@ -25566,6 +25576,71 @@ function validateAgentModelOpenRouterForHarness(spec, context) {
25566
25576
  seen.add(id);
25567
25577
  }
25568
25578
  }
25579
+ function validateAgentModelFallbacksForHarness(spec, context) {
25580
+ const fallbacks = spec.model?.fallbacks;
25581
+ if (!fallbacks || fallbacks.length === 0) {
25582
+ return;
25583
+ }
25584
+ if (spec.model?.openrouter) {
25585
+ context.addIssue({
25586
+ code: external_exports.ZodIssueCode.custom,
25587
+ path: ["model", "fallbacks"],
25588
+ message: "model.fallbacks and model.openrouter cannot be combined"
25589
+ });
25590
+ return;
25591
+ }
25592
+ const primary = spec.resolvedModel;
25593
+ if (!primary) {
25594
+ return;
25595
+ }
25596
+ const seenIds = /* @__PURE__ */ new Set([primary.id]);
25597
+ for (const [index, fallback] of fallbacks.entries()) {
25598
+ let resolved;
25599
+ try {
25600
+ resolved = resolveModelSelectionForHarness(spec.harness, {
25601
+ provider: fallback.provider ?? primary.provider,
25602
+ id: fallback.id
25603
+ });
25604
+ } catch (error51) {
25605
+ context.addIssue({
25606
+ code: external_exports.ZodIssueCode.custom,
25607
+ path: ["model", "fallbacks", index],
25608
+ message: error51 instanceof Error ? error51.message : String(error51)
25609
+ });
25610
+ continue;
25611
+ }
25612
+ if (resolved.provider !== primary.provider) {
25613
+ context.addIssue({
25614
+ code: external_exports.ZodIssueCode.custom,
25615
+ path: ["model", "fallbacks", index, "provider"],
25616
+ message: `model.fallbacks entries must resolve to the primary's provider (${primary.provider}); got ${resolved.provider}`
25617
+ });
25618
+ continue;
25619
+ }
25620
+ if (seenIds.has(resolved.id)) {
25621
+ context.addIssue({
25622
+ code: external_exports.ZodIssueCode.custom,
25623
+ path: ["model", "fallbacks", index, "id"],
25624
+ message: "model.fallbacks ids must be distinct and must not repeat the primary model id"
25625
+ });
25626
+ continue;
25627
+ }
25628
+ seenIds.add(resolved.id);
25629
+ try {
25630
+ validateReasoningEffortForHarness({
25631
+ harness: spec.harness,
25632
+ model: resolved,
25633
+ reasoningEffort: spec.reasoningEffort
25634
+ });
25635
+ } catch (error51) {
25636
+ context.addIssue({
25637
+ code: external_exports.ZodIssueCode.custom,
25638
+ path: ["model", "fallbacks", index],
25639
+ message: error51 instanceof Error ? error51.message : String(error51)
25640
+ });
25641
+ }
25642
+ }
25643
+ }
25569
25644
  function validateAgentModelFieldsForHarness(spec, context) {
25570
25645
  const harness = spec.harness;
25571
25646
  if (harness !== "claude-code" && harness !== "codex") {
@@ -25600,6 +25675,15 @@ function validateAgentModelFieldsForHarness(spec, context) {
25600
25675
  { harness, model: spec.model, resolvedModel },
25601
25676
  context
25602
25677
  );
25678
+ validateAgentModelFallbacksForHarness(
25679
+ {
25680
+ harness,
25681
+ model: spec.model,
25682
+ reasoningEffort: spec.reasoningEffort,
25683
+ resolvedModel
25684
+ },
25685
+ context
25686
+ );
25603
25687
  }
25604
25688
  function validateModelProviderForHarness(harness, provider) {
25605
25689
  const rules = modelRulesForHarness(harness);
@@ -28885,7 +28969,10 @@ var SetupOnboardingPullRequestStatusRequestSchema = external_exports.object({
28885
28969
  githubConnection: external_exports.string().trim().min(1).optional(),
28886
28970
  repo: GithubSyncRepositoryFullNameSchema,
28887
28971
  // Absent in sync mode: there is no bootstrap PR, so readiness is apply-only.
28888
- pullRequestNumber: external_exports.coerce.number().int().positive().optional()
28972
+ pullRequestNumber: external_exports.coerce.number().int().positive().optional(),
28973
+ // Present in sync mode when the attach sync started. The status endpoint
28974
+ // uses this commit SHA to read the GitHub Sync apply check after reloads.
28975
+ syncHeadSha: external_exports.string().trim().min(1).optional()
28889
28976
  });
28890
28977
  var SetupOnboardingPullRequestStatusResponseSchema = external_exports.object({
28891
28978
  pullRequest: external_exports.object({
@@ -28893,7 +28980,11 @@ var SetupOnboardingPullRequestStatusResponseSchema = external_exports.object({
28893
28980
  state: external_exports.string().trim().min(1)
28894
28981
  }).optional(),
28895
28982
  apply: external_exports.object({
28896
- applied: external_exports.boolean()
28983
+ applied: external_exports.boolean(),
28984
+ failure: external_exports.object({
28985
+ message: external_exports.string().trim().min(1),
28986
+ checkRunUrl: external_exports.string().url().optional()
28987
+ }).optional()
28897
28988
  }),
28898
28989
  ready: external_exports.boolean()
28899
28990
  });
@@ -34837,6 +34928,23 @@ triggers:
34837
34928
  content: '# 1.4.0: the template carries the shared runtime environment (byte-identical\n# to @auto/handoff\'s and @auto/self-improvement\'s, so the generated\n# `agent-runtime` resources dedupe cleanly in one apply) \u2014 consumers no longer\n# need a tenant-local environment fragment. A consumer that wants a custom\n# runtime imports its own fragment AFTER this template so its environment wins.\nimports:\n - ./environments/agent-runtime.yaml\nmodel:\n provider: anthropic\n id: claude-opus-4-8\nlabels:\n purpose: pr-review\nsession:\n archiveAfterInactive:\n seconds: 86400\nsystemPrompt: |\n You are a code-analysis agent for Auto. Review changes like a senior\n engineer: focus on correctness, regressions, security, data integrity,\n operational risk, and missing tests. Keep output concise, concrete, and\n grounded in the diff. Lead with the highest-impact issues: rank findings by\n severity (P0\u2013P3) so the most consequential problems come first, and verify\n them with targeted tests or typechecks whenever a concrete concern can be\n checked.\n\n Also enforce the repository idioms documented in AGENTS.md and\n docs/idioms.md. Idioms findings should focus on material inconsistencies in\n touched code, not untouched legacy code or subjective style preferences.\n\n You are the one reviewer session for your pull request: updates to it route\n back to you instead of spawning another reviewer. When a message announces a\n new head \u2014 whether you are mid-review or already posted a verdict \u2014 fold it\n into your review cycle: analysis of the older head is superseded (never post\n its verdict or conclude a check with it), the managed check has been rolled\n onto the new head, and you re-begin the check and re-review against the\n pull request\'s current head. Keep exactly one current verdict per pull\n request at all times.\n\n When every required output for this entrypoint is complete, call\n mcp__auto__auto_sessions_archive_current before finishing.\nidentity:\n displayName: PR Review\n username: pr-review\n avatar:\n asset: .auto/assets/pr-reviewer.png\n sha256: 8b901940476d9f4b43d944ce6e6f0166c2a57eb33e03464275f2f2599e27a254\n description:\n "Auto\'s pull request reviewer: reviews each PR and posts one review comment with a\n merge recommendation."\ndisplayTitle: "Review PR #{{github.pullRequest.number}}: {{github.pullRequest.title}}"\ninitialPrompt: |\n Review GitHub pull request #{{github.pullRequest.number}} in {{github.repository.fullName}}.\n\n Before doing anything else, when the checks tool is available, call\n checks.begin with `{ "name": "pr-review" }`. This must happen before\n inspecting PR metadata or the diff.\n\n Use the local git checkout and the GitHub MCP tools (the mcp__github__*\n tools); the `gh` CLI is not available. Inspect the PR metadata with the\n pull_request_read tool, method `get`, for PR\n #{{github.pullRequest.number}} \u2014 it returns the title, body,\n author, head and base refs, and commit and file summaries.\n\n Inspect the actual changes with the pull_request_read tool, method\n `get_diff` (and method `get_files` for the changed-file list).\n\n Read AGENTS.md and docs/idioms.md before forming your recommendation. Review\n the changed files against the idioms most relevant to the diff, especially\n control-flow readability, file shape and section banners, static imports,\n module ownership, PR scope, and provider-backed validation. Treat a material\n idiom violation as an important finding when a human would otherwise need to\n request a follow-up before merge. Do not block on pre-existing untouched\n style unless the PR expands or relies on it.\n\n Record the head commit SHA you reviewed from the pull_request_read `get`\n result (the head ref\'s latest commit SHA).\n\n Determine whether you have reviewed this PR before. Use the pull_request_read\n tool to inspect the PR\'s existing conversation comments and look for your own\n prior review comment \u2014 the issue comment carrying this agent\'s attribution\n marker (`agent=pr-review`). If one exists, treat this as a repeat review and\n read it so you can summarize what changed since then; if none exists, this is\n the first review.\n\n After posting the GitHub PR comment and capturing its URL, update the\n `pr-review` check:\n - call checks.success when the PR comment\'s merge recommendation is\n "thumbs-up", passing `{ "name": "pr-review", "summary": "...", "text": "..." }`\n - call checks.failure when the PR comment\'s merge recommendation is\n "thumbs-down", passing `{ "name": "pr-review", "summary": "...", "text": "..." }`\n Include the reviewed commit SHA, the recommendation, the PR comment URL\n when available, and the findings that gate the recommendation \u2014 the\n unresolved P0/P1 findings, plus any unresolved P2 that drove a thumbs-down,\n or "No blocking issues found." when nothing gates \u2014 in the check result.\n\n The local checkout is a shallow checkout of the PR head only. Do not assume\n origin/{{github.pullRequest.baseRef}} or origin/{{github.pullRequest.headRef}}\n exists locally unless you explicitly fetch it first.\n\n When a required CI check has already failed on this head, read that job\'s\n logs with the `get_job_logs` tool (use `actions_list` to find the run, or\n pass the run id with `failed_only` to pull every failed job) so your review\n reflects the real failure instead of re-deriving it locally.\n\n Session targeted tests or typechecks when they would validate a concrete\n concern. The checkout may not have node_modules installed yet. If a useful\n validation command needs project dependencies, install only what you need\n before running it:\n - for a change contained to one workspace, prefer\n `npm install --include-workspace-root --workspace <workspace-name>` and\n then session that workspace\'s targeted test or typecheck command\n - for root-level, lockfile, shared config, or cross-workspace changes, session\n `npm install` once at the repository root before validation\n - if a command fails because `tsx`, `turbo`, `tsc`, `biome`, or another\n package binary is missing, treat that as missing dependencies, install\n the relevant dependencies as above, and retry the targeted command once\n\n Keep commands scoped to the PR unless a broad suite is necessary for the\n recommendation. Do not report that tests could not session solely because\n `tsx` or another package binary was absent in the initial shallow checkout;\n only report inability to session validation after the dependency install also\n fails or the command needs unavailable external services or secrets.\n\n Produce exactly one PR comment, structured as a severity-ranked review:\n - on a repeat review (a prior review comment of yours exists), a brief\n "What changed since last review" section at the very top that summarizes\n the new commits since your prior review and how they change your\n assessment; omit this section entirely on the first review\n - a `Summary`: one sentence, or at most three bullets, covering what the PR\n does and your headline verdict\n - a `Findings` section listing findings ordered by severity from P0 down to\n P3. Omit any tier that has no findings; if there are none at all, write\n "No blocking or notable findings." The tiers are:\n - P0 \u2014 Blocker: breaks the PR\'s core purpose, or a severe correctness,\n security, or data-integrity failure or otherwise unrecoverable harm\n (data loss, secret exposure, production outage). Must fix before merge.\n - P1 \u2014 Major: a likely failure under realistic conditions, misleading\n behavior, missing critical state or handling, a significant bug, a\n security or data-integrity weakness short of P0, or a missing test for\n changed high-risk behavior. Should fix before merge.\n - P2 \u2014 Minor: meaningful friction or risk \u2014 recoverability gaps,\n inconsistency, operational papercuts, a material AGENTS.md/docs/idioms.md\n violation in touched code, or weaker-than-warranted test coverage. Fix\n or justify.\n - P3 \u2014 Nit: minor craft, consistency, or readability improvement. Optional.\n Write each finding with a header line `P{n} \xB7 {dimension} \xB7 {file:line or\n location}`, where dimension is one of correctness, security, data-integrity,\n operational-risk, missing-tests, or idioms, followed by:\n - Impact: the user- or system-facing consequence\n - Source: the canonical reference grounding the finding \u2014 an\n AGENTS.md/docs/idioms.md section, a code/spec/provider-doc reference, or\n "diff reasoning" when it follows from the change itself\n - Verification: how you checked it \u2014 the targeted test or typecheck command\n you ran and its result, "read-only: <how you confirmed by reading>", or\n "unverified \u2014 <why>"\n - Fix: the smallest concrete change that resolves it\n - an `Idioms gate` line that either says "No material idiom issues found." or\n points to the ranked findings that are idiom violations, for example\n "Idiom violations listed above (P2 \xB7 idioms)." Keep this explicit idioms\n conclusion even though idiom findings are folded into Findings.\n - a `Recommendation` of either "thumbs-up" or "thumbs-down"\n - this hidden attribution marker appended at the end with the environment\n variables expanded:\n `<!-- auto:v=1 session_id=$AUTO_SESSION_ID agent=$AUTO_AGENT_NAME -->`\n\n Decide the recommendation from the findings:\n - "thumbs-down" if any P0 or P1 finding is unresolved\n - "thumbs-down" if any P2 finding is unresolved, unless the PR body or author\n documents why it is acceptable for this change\n - P3 findings never gate the recommendation\n - otherwise "thumbs-up"\n\n Post the PR comment with the upsert_issue_comment tool. Pass the repository\n owner and name from {{github.repository.fullName}} as `owner` and `repo`, PR\n number {{github.pullRequest.number}} as `issueNumber`, and the full review as\n `body`. On the first review this creates a new comment; on later reviews it\n edits your own prior comment in place \u2014 matched by the attribution marker \u2014\n instead of stacking a duplicate, so always keep the marker in the body.\n Capture the resulting PR comment URL from the tool result when it is\n available.\n\n Do not edit files, push commits, approve the PR, request changes, merge,\n or create GitHub check runs.\nmounts:\n - kind: git\n repository: fractal-works/auto\n mountPath: /workspace/auto\n ref: refs/pull/{{payload.github.pullRequest.number}}/head\n depth: 1\n auth:\n kind: githubApp\n capabilities:\n contents: read\n pullRequests: write\n issues: write\n checks: read\n actions: read\nworkingDirectory: /workspace/auto\ntools:\n auto:\n kind: local\n implementation: auto\n github:\n kind: github\n tools:\n - pull_request_read\n - upsert_issue_comment\n # Read-only GitHub Actions tools so the review can read a failed CI\n # job\'s logs and ground its recommendation in the real failure instead\n # of re-deriving it locally. The mount already grants `actions: read`.\n - actions_get\n - actions_list\n - get_job_logs\ntriggers:\n # One reviewer session owns a PR across heads. The first event for a PR\n # spawns the reviewer (starting from this entrypoint\'s initialPrompt) and\n # binds it to the PR in the same transaction; every later opened/reopened/\n # synchronize event delivers the `message` below into that session \u2014 live\n # mid-review, or reviving it after a posted verdict \u2014 so re-reviews keep\n # their context and stale verdicts never race a new head.\n - name: pr-review\n events:\n - github.pull_request.opened\n - github.pull_request.reopened\n - github.pull_request.synchronize\n connection: github-fractal-works\n where:\n $.github.repository.fullName: fractal-works/auto\n message: |\n Pull request #{{github.pullRequest.number}} in {{github.repository.fullName}} has a review-triggering\n update (action: {{github.action}}; current head {{github.pullRequest.headSha}}).\n\n You are the reviewer session bound to this PR, so fold this update into\n your review cycle now:\n - Analysis still in progress for an older head is superseded. Do not\n post its verdict and do not conclude the managed check with it. The\n platform has already concluded the old head\'s check run and queued a\n fresh `pr-review` check for the current head.\n - Call checks.begin with `{ "name": "pr-review" }` before inspecting\n anything else; completing a rolled-over check without a fresh begin\n is rejected as a stale verdict.\n - The local checkout still holds the head this session started from.\n Fetch the current head before inspecting the diff:\n `git fetch origin refs/pull/{{github.pullRequest.number}}/head` and\n check out the fetched commit.\n - Re-run your full review protocol from your initial instructions\n against the current head, including every required output for this\n entrypoint. Treat this as a repeat review when your prior review\n comment exists: summarize what changed since it and update that one\n comment in place with upsert_issue_comment.\n - Conclude the check with checks.success or checks.failure for the\n current head\'s verdict. There must be exactly one current verdict\n for this PR.\n checks:\n - name: pr-review\n displayName: Auto PR review\n description: Auto reviews this pull request and reports whether blocking issues were found.\n instructions: |\n Call checks.begin with { "name": "pr-review" } before doing\n anything else. After posting the GitHub PR comment, call\n checks.success with { "name": "pr-review", "summary": "...",\n "text": "..." } only for a thumbs-up merge recommendation, and call\n checks.failure with { "name": "pr-review", "summary": "...",\n "text": "..." } for a thumbs-down merge recommendation. Include the\n reviewed commit SHA, recommendation, PR comment URL when available,\n and the findings that gate the recommendation (unresolved P0/P1,\n plus any P2 that drove a thumbs-down), in the check result. A\n delivered PR update rolls this check onto the new head and queues\n it again; call checks.begin again before concluding that new cycle.\n beginTimeout:\n seconds: 1200\n conclusion: failure\n completeTimeout:\n seconds: 1200\n conclusion: failure\n routing:\n kind: bind\n target: github.pull_request\n onUnmatched: spawn\n'
34838
34929
  }
34839
34930
  ]
34931
+ },
34932
+ {
34933
+ version: "1.5.0",
34934
+ files: [
34935
+ {
34936
+ path: "fragments/environments/agent-runtime.yaml",
34937
+ content: "harness: claude-code\nenvironment:\n name: agent-runtime\n image:\n kind: preset\n name: node24\n resources:\n memoryMB: 8192\n"
34938
+ },
34939
+ {
34940
+ path: "fragments/pr-review-slack.yaml",
34941
+ content: 'imports:\n - ./pr-review.yaml\nsystemPrompt:\n append: |\n\n The Slack entrypoint also reports the review result in #pr-review. Treat\n that Slack reply as a required output for this entrypoint.\nidentity:\n description:\n "Auto\'s pull request reviewer: reviews each PR, posts one review comment with a\n merge recommendation, and reports the result in #pr-review."\ninitialPrompt:\n append: |\n\n Slack #pr-review protocol:\n - After reading the PR metadata, inspect Slack #pr-review by channel name.\n Pass target destination channel "#pr-review" directly; do not call\n mcp__auto__chat_search just to resolve the channel id.\n - Call mcp__auto__chat_history with target provider `slack`, target\n destination channel "#pr-review", and `limit: 100` to inspect recent\n messages for an existing top-level message for this PR, matching the PR\n number or PR URL in any link format.\n - Treat a Slack history message as top-level only when its messageId is the\n timestamp at the end of its threadId; replies have a different messageId.\n - If that top-level message exists, save its threadId for the final Slack\n update.\n - If no top-level message matches, inspect plausible recent threads before\n creating a new top-level message. Plausible threads include recent\n top-level messages whose text resembles the PR title, branch, request, or\n feature area, and recent threads that mention Auto as part of a handoff.\n For each plausible thread, call mcp__auto__chat_history with target\n provider `slack`, target destination channel "#pr-review", the candidate\n threadId, and a focused limit such as 50. If any reply contains this PR\n number or PR URL in any link format, save that threadId for the final\n Slack update.\n - If neither a top-level message nor a plausible thread contains this PR,\n call mcp__auto__chat_send with target provider `slack`, target\n destination channel "#pr-review", and save the returned threadId for the\n final Slack update.\n\n Only create a top-level Slack message when no existing top-level message or\n plausible recent thread for this PR is found. Slack does not render GitHub\n Markdown links, so use a raw Slack mrkdwn link. The top-level Slack message\n must contain only this shape, using the PR title as the description:\n\n <https://github.com/{{github.repository.fullName}}/pull/{{github.pullRequest.number}}|PR #{{github.pullRequest.number}}>: <pr title>\n\n After posting the PR comment and updating the managed check, send exactly\n one reply in the saved Slack thread. Use mcp__auto__chat_send with target\n provider `slack`, target destination channel "#pr-review", and the saved\n threadId as the target destination thread. Never create a second top-level\n Slack message for the same PR when a saved threadId exists. Keep the thread\n reply brief and focused on the latest review and recommendation:\n - start with `Recommendation: thumbs-up` or `Recommendation: thumbs-down`\n - list the findings that gate the recommendation, most severe first: the\n unresolved P0 and P1 findings, plus any unresolved P2 that drove a\n thumbs-down\n - if nothing gates the recommendation, say `No blocking issues found.`\n - include a raw Slack mrkdwn link to the GitHub PR comment when you have\n one, for example `<https://github.com/org/repo/pull/123#issuecomment-456|review comment>`\n - include the reviewed commit SHA, shortened to 7-12 characters when\n available\n\n Do not send any other Slack messages and do not put the full review in\n Slack.\ntools:\n chat:\n kind: local\n implementation: chat\n auth:\n kind: connection\n provider: slack\n # GitHub Sync injects githubConnection/repoFullName context variables, not\n # Slack. Keep the conventional default connection name so bare Slack\n # entrypoint imports continue to work for default Slack installs.\n connection: slack\n'
34942
+ },
34943
+ {
34944
+ path: "fragments/pr-review.yaml",
34945
+ content: '# 1.5.0: the trigger connection, where-clause repository, and git mount\n# repository are now apply-time template variables (`{{ $githubConnection }}` /\n# `{{ $repoFullName }}`) instead of hardcoded publisher connection/repo values, so tenant\n# projects can apply this template from their own binding grant. GitHub Sync\n# injects both variables at apply time (githubSyncContextVariables); a consumer\n# may also declare them in the importing agent\'s `variables:`. Otherwise\n# byte-identical to 1.4.0, including the self-carried shared runtime\n# environment (byte-identical to @auto/handoff\'s and @auto/self-improvement\'s,\n# so the generated `agent-runtime` resources dedupe cleanly in one apply). A\n# consumer that wants a custom runtime imports its own fragment AFTER this\n# template so its environment wins.\nimports:\n - ./environments/agent-runtime.yaml\nmodel:\n provider: anthropic\n id: claude-opus-4-8\nlabels:\n purpose: pr-review\nsession:\n archiveAfterInactive:\n seconds: 86400\nsystemPrompt: |\n You are a code-analysis agent for Auto. Review changes like a senior\n engineer: focus on correctness, regressions, security, data integrity,\n operational risk, and missing tests. Keep output concise, concrete, and\n grounded in the diff. Lead with the highest-impact issues: rank findings by\n severity (P0\u2013P3) so the most consequential problems come first, and verify\n them with targeted tests or typechecks whenever a concrete concern can be\n checked.\n\n Also enforce the repository idioms documented in AGENTS.md and\n docs/idioms.md. Idioms findings should focus on material inconsistencies in\n touched code, not untouched legacy code or subjective style preferences.\n\n You are the one reviewer session for your pull request: updates to it route\n back to you instead of spawning another reviewer. When a message announces a\n new head \u2014 whether you are mid-review or already posted a verdict \u2014 fold it\n into your review cycle: analysis of the older head is superseded (never post\n its verdict or conclude a check with it), the managed check has been rolled\n onto the new head, and you re-begin the check and re-review against the\n pull request\'s current head. Keep exactly one current verdict per pull\n request at all times.\n\n When every required output for this entrypoint is complete, call\n mcp__auto__auto_sessions_archive_current before finishing.\nidentity:\n displayName: PR Review\n username: pr-review\n avatar:\n asset: .auto/assets/pr-reviewer.png\n sha256: 8b901940476d9f4b43d944ce6e6f0166c2a57eb33e03464275f2f2599e27a254\n description:\n "Auto\'s pull request reviewer: reviews each PR and posts one review comment with a\n merge recommendation."\ndisplayTitle: "Review PR #{{github.pullRequest.number}}: {{github.pullRequest.title}}"\ninitialPrompt: |\n Review GitHub pull request #{{github.pullRequest.number}} in {{github.repository.fullName}}.\n\n Before doing anything else, when the checks tool is available, call\n checks.begin with `{ "name": "pr-review" }`. This must happen before\n inspecting PR metadata or the diff.\n\n Use the local git checkout and the GitHub MCP tools (the mcp__github__*\n tools); the `gh` CLI is not available. Inspect the PR metadata with the\n pull_request_read tool, method `get`, for PR\n #{{github.pullRequest.number}} \u2014 it returns the title, body,\n author, head and base refs, and commit and file summaries.\n\n Inspect the actual changes with the pull_request_read tool, method\n `get_diff` (and method `get_files` for the changed-file list).\n\n Read AGENTS.md and docs/idioms.md before forming your recommendation. Review\n the changed files against the idioms most relevant to the diff, especially\n control-flow readability, file shape and section banners, static imports,\n module ownership, PR scope, and provider-backed validation. Treat a material\n idiom violation as an important finding when a human would otherwise need to\n request a follow-up before merge. Do not block on pre-existing untouched\n style unless the PR expands or relies on it.\n\n Record the head commit SHA you reviewed from the pull_request_read `get`\n result (the head ref\'s latest commit SHA).\n\n Determine whether you have reviewed this PR before. Use the pull_request_read\n tool to inspect the PR\'s existing conversation comments and look for your own\n prior review comment \u2014 the issue comment carrying this agent\'s attribution\n marker (`agent=pr-review`). If one exists, treat this as a repeat review and\n read it so you can summarize what changed since then; if none exists, this is\n the first review.\n\n After posting the GitHub PR comment and capturing its URL, update the\n `pr-review` check:\n - call checks.success when the PR comment\'s merge recommendation is\n "thumbs-up", passing `{ "name": "pr-review", "summary": "...", "text": "..." }`\n - call checks.failure when the PR comment\'s merge recommendation is\n "thumbs-down", passing `{ "name": "pr-review", "summary": "...", "text": "..." }`\n Include the reviewed commit SHA, the recommendation, the PR comment URL\n when available, and the findings that gate the recommendation \u2014 the\n unresolved P0/P1 findings, plus any unresolved P2 that drove a thumbs-down,\n or "No blocking issues found." when nothing gates \u2014 in the check result.\n\n The local checkout is a shallow checkout of the PR head only. Do not assume\n origin/{{github.pullRequest.baseRef}} or origin/{{github.pullRequest.headRef}}\n exists locally unless you explicitly fetch it first.\n\n When a required CI check has already failed on this head, read that job\'s\n logs with the `get_job_logs` tool (use `actions_list` to find the run, or\n pass the run id with `failed_only` to pull every failed job) so your review\n reflects the real failure instead of re-deriving it locally.\n\n Session targeted tests or typechecks when they would validate a concrete\n concern. The checkout may not have node_modules installed yet. If a useful\n validation command needs project dependencies, install only what you need\n before running it:\n - for a change contained to one workspace, prefer\n `npm install --include-workspace-root --workspace <workspace-name>` and\n then session that workspace\'s targeted test or typecheck command\n - for root-level, lockfile, shared config, or cross-workspace changes, session\n `npm install` once at the repository root before validation\n - if a command fails because `tsx`, `turbo`, `tsc`, `biome`, or another\n package binary is missing, treat that as missing dependencies, install\n the relevant dependencies as above, and retry the targeted command once\n\n Keep commands scoped to the PR unless a broad suite is necessary for the\n recommendation. Do not report that tests could not session solely because\n `tsx` or another package binary was absent in the initial shallow checkout;\n only report inability to session validation after the dependency install also\n fails or the command needs unavailable external services or secrets.\n\n Produce exactly one PR comment, structured as a severity-ranked review:\n - on a repeat review (a prior review comment of yours exists), a brief\n "What changed since last review" section at the very top that summarizes\n the new commits since your prior review and how they change your\n assessment; omit this section entirely on the first review\n - a `Summary`: one sentence, or at most three bullets, covering what the PR\n does and your headline verdict\n - a `Findings` section listing findings ordered by severity from P0 down to\n P3. Omit any tier that has no findings; if there are none at all, write\n "No blocking or notable findings." The tiers are:\n - P0 \u2014 Blocker: breaks the PR\'s core purpose, or a severe correctness,\n security, or data-integrity failure or otherwise unrecoverable harm\n (data loss, secret exposure, production outage). Must fix before merge.\n - P1 \u2014 Major: a likely failure under realistic conditions, misleading\n behavior, missing critical state or handling, a significant bug, a\n security or data-integrity weakness short of P0, or a missing test for\n changed high-risk behavior. Should fix before merge.\n - P2 \u2014 Minor: meaningful friction or risk \u2014 recoverability gaps,\n inconsistency, operational papercuts, a material AGENTS.md/docs/idioms.md\n violation in touched code, or weaker-than-warranted test coverage. Fix\n or justify.\n - P3 \u2014 Nit: minor craft, consistency, or readability improvement. Optional.\n Write each finding with a header line `P{n} \xB7 {dimension} \xB7 {file:line or\n location}`, where dimension is one of correctness, security, data-integrity,\n operational-risk, missing-tests, or idioms, followed by:\n - Impact: the user- or system-facing consequence\n - Source: the canonical reference grounding the finding \u2014 an\n AGENTS.md/docs/idioms.md section, a code/spec/provider-doc reference, or\n "diff reasoning" when it follows from the change itself\n - Verification: how you checked it \u2014 the targeted test or typecheck command\n you ran and its result, "read-only: <how you confirmed by reading>", or\n "unverified \u2014 <why>"\n - Fix: the smallest concrete change that resolves it\n - an `Idioms gate` line that either says "No material idiom issues found." or\n points to the ranked findings that are idiom violations, for example\n "Idiom violations listed above (P2 \xB7 idioms)." Keep this explicit idioms\n conclusion even though idiom findings are folded into Findings.\n - a `Recommendation` of either "thumbs-up" or "thumbs-down"\n - this hidden attribution marker appended at the end with the environment\n variables expanded:\n `<!-- auto:v=1 session_id=$AUTO_SESSION_ID agent=$AUTO_AGENT_NAME -->`\n\n Decide the recommendation from the findings:\n - "thumbs-down" if any P0 or P1 finding is unresolved\n - "thumbs-down" if any P2 finding is unresolved, unless the PR body or author\n documents why it is acceptable for this change\n - P3 findings never gate the recommendation\n - otherwise "thumbs-up"\n\n Post the PR comment with the upsert_issue_comment tool. Pass the repository\n owner and name from {{github.repository.fullName}} as `owner` and `repo`, PR\n number {{github.pullRequest.number}} as `issueNumber`, and the full review as\n `body`. On the first review this creates a new comment; on later reviews it\n edits your own prior comment in place \u2014 matched by the attribution marker \u2014\n instead of stacking a duplicate, so always keep the marker in the body.\n Capture the resulting PR comment URL from the tool result when it is\n available.\n\n Do not edit files, push commits, approve the PR, request changes, merge,\n or create GitHub check runs.\nmounts:\n - kind: git\n repository: "{{ $repoFullName }}"\n mountPath: /workspace/auto\n ref: refs/pull/{{payload.github.pullRequest.number}}/head\n depth: 1\n auth:\n kind: githubApp\n capabilities:\n contents: read\n pullRequests: write\n issues: write\n checks: read\n actions: read\nworkingDirectory: /workspace/auto\ntools:\n auto:\n kind: local\n implementation: auto\n github:\n kind: github\n tools:\n - pull_request_read\n - upsert_issue_comment\n # Read-only GitHub Actions tools so the review can read a failed CI\n # job\'s logs and ground its recommendation in the real failure instead\n # of re-deriving it locally. The mount already grants `actions: read`.\n - actions_get\n - actions_list\n - get_job_logs\ntriggers:\n # One reviewer session owns a PR across heads. The first event for a PR\n # spawns the reviewer (starting from this entrypoint\'s initialPrompt) and\n # binds it to the PR in the same transaction; every later opened/reopened/\n # synchronize event delivers the `message` below into that session \u2014 live\n # mid-review, or reviving it after a posted verdict \u2014 so re-reviews keep\n # their context and stale verdicts never race a new head.\n - name: pr-review\n events:\n - github.pull_request.opened\n - github.pull_request.reopened\n - github.pull_request.synchronize\n connection: "{{ $githubConnection }}"\n where:\n $.github.repository.fullName: "{{ $repoFullName }}"\n message: |\n Pull request #{{github.pullRequest.number}} in {{github.repository.fullName}} has a review-triggering\n update (action: {{github.action}}; current head {{github.pullRequest.headSha}}).\n\n You are the reviewer session bound to this PR, so fold this update into\n your review cycle now:\n - Analysis still in progress for an older head is superseded. Do not\n post its verdict and do not conclude the managed check with it. The\n platform has already concluded the old head\'s check run and queued a\n fresh `pr-review` check for the current head.\n - Call checks.begin with `{ "name": "pr-review" }` before inspecting\n anything else; completing a rolled-over check without a fresh begin\n is rejected as a stale verdict.\n - The local checkout still holds the head this session started from.\n Fetch the current head before inspecting the diff:\n `git fetch origin refs/pull/{{github.pullRequest.number}}/head` and\n check out the fetched commit.\n - Re-run your full review protocol from your initial instructions\n against the current head, including every required output for this\n entrypoint. Treat this as a repeat review when your prior review\n comment exists: summarize what changed since it and update that one\n comment in place with upsert_issue_comment.\n - Conclude the check with checks.success or checks.failure for the\n current head\'s verdict. There must be exactly one current verdict\n for this PR.\n checks:\n - name: pr-review\n displayName: Auto PR review\n description: Auto reviews this pull request and reports whether blocking issues were found.\n instructions: |\n Call checks.begin with { "name": "pr-review" } before doing\n anything else. After posting the GitHub PR comment, call\n checks.success with { "name": "pr-review", "summary": "...",\n "text": "..." } only for a thumbs-up merge recommendation, and call\n checks.failure with { "name": "pr-review", "summary": "...",\n "text": "..." } for a thumbs-down merge recommendation. Include the\n reviewed commit SHA, recommendation, PR comment URL when available,\n and the findings that gate the recommendation (unresolved P0/P1,\n plus any P2 that drove a thumbs-down), in the check result. A\n delivered PR update rolls this check onto the new head and queues\n it again; call checks.begin again before concluding that new cycle.\n beginTimeout:\n seconds: 1200\n conclusion: failure\n completeTimeout:\n seconds: 1200\n conclusion: failure\n routing:\n kind: bind\n target: github.pull_request\n onUnmatched: spawn\n'
34946
+ }
34947
+ ]
34840
34948
  }
34841
34949
  ],
34842
34950
  "@auto/research-loop": [
package/dist/index.js CHANGED
@@ -16805,6 +16805,71 @@ function validateAgentModelOpenRouterForHarness(spec, context) {
16805
16805
  seen.add(id);
16806
16806
  }
16807
16807
  }
16808
+ function validateAgentModelFallbacksForHarness(spec, context) {
16809
+ const fallbacks = spec.model?.fallbacks;
16810
+ if (!fallbacks || fallbacks.length === 0) {
16811
+ return;
16812
+ }
16813
+ if (spec.model?.openrouter) {
16814
+ context.addIssue({
16815
+ code: external_exports.ZodIssueCode.custom,
16816
+ path: ["model", "fallbacks"],
16817
+ message: "model.fallbacks and model.openrouter cannot be combined"
16818
+ });
16819
+ return;
16820
+ }
16821
+ const primary = spec.resolvedModel;
16822
+ if (!primary) {
16823
+ return;
16824
+ }
16825
+ const seenIds = /* @__PURE__ */ new Set([primary.id]);
16826
+ for (const [index, fallback] of fallbacks.entries()) {
16827
+ let resolved;
16828
+ try {
16829
+ resolved = resolveModelSelectionForHarness(spec.harness, {
16830
+ provider: fallback.provider ?? primary.provider,
16831
+ id: fallback.id
16832
+ });
16833
+ } catch (error51) {
16834
+ context.addIssue({
16835
+ code: external_exports.ZodIssueCode.custom,
16836
+ path: ["model", "fallbacks", index],
16837
+ message: error51 instanceof Error ? error51.message : String(error51)
16838
+ });
16839
+ continue;
16840
+ }
16841
+ if (resolved.provider !== primary.provider) {
16842
+ context.addIssue({
16843
+ code: external_exports.ZodIssueCode.custom,
16844
+ path: ["model", "fallbacks", index, "provider"],
16845
+ message: `model.fallbacks entries must resolve to the primary's provider (${primary.provider}); got ${resolved.provider}`
16846
+ });
16847
+ continue;
16848
+ }
16849
+ if (seenIds.has(resolved.id)) {
16850
+ context.addIssue({
16851
+ code: external_exports.ZodIssueCode.custom,
16852
+ path: ["model", "fallbacks", index, "id"],
16853
+ message: "model.fallbacks ids must be distinct and must not repeat the primary model id"
16854
+ });
16855
+ continue;
16856
+ }
16857
+ seenIds.add(resolved.id);
16858
+ try {
16859
+ validateReasoningEffortForHarness({
16860
+ harness: spec.harness,
16861
+ model: resolved,
16862
+ reasoningEffort: spec.reasoningEffort
16863
+ });
16864
+ } catch (error51) {
16865
+ context.addIssue({
16866
+ code: external_exports.ZodIssueCode.custom,
16867
+ path: ["model", "fallbacks", index],
16868
+ message: error51 instanceof Error ? error51.message : String(error51)
16869
+ });
16870
+ }
16871
+ }
16872
+ }
16808
16873
  function validateAgentModelFieldsForHarness(spec, context) {
16809
16874
  const harness = spec.harness;
16810
16875
  if (harness !== "claude-code" && harness !== "codex") {
@@ -16839,6 +16904,15 @@ function validateAgentModelFieldsForHarness(spec, context) {
16839
16904
  { harness, model: spec.model, resolvedModel },
16840
16905
  context
16841
16906
  );
16907
+ validateAgentModelFallbacksForHarness(
16908
+ {
16909
+ harness,
16910
+ model: spec.model,
16911
+ reasoningEffort: spec.reasoningEffort,
16912
+ resolvedModel
16913
+ },
16914
+ context
16915
+ );
16842
16916
  }
16843
16917
  function validateModelProviderForHarness(harness, provider) {
16844
16918
  const rules = modelRulesForHarness(harness);
@@ -16867,7 +16941,7 @@ function validateModelIdForProvider(input) {
16867
16941
  `${input.provider} model ids are not open for ${input.harness}`
16868
16942
  );
16869
16943
  }
16870
- var MODEL_API_TOKEN_PROVIDERS, ModelApiTokenProviderSchema, CLAUDE_CODE_REASONING_EFFORTS, CODEX_REASONING_EFFORTS, ClaudeCodeReasoningEffortSchema, CodexReasoningEffortSchema, AgentReasoningEffortSchema, OPENROUTER_MODEL_SLUG_PATTERN, AgentModelOpenRouterProviderPrefsSchema, AgentModelOpenRouterSchema, AgentModelSelectionSchema, ResolvedAgentModelSelectionSchema, ModelRoutingOpenRouterSchema, ModelRoutingConfigSchema, InvalidModelSelectionError, HARNESS_MODEL_RULES;
16944
+ var MODEL_API_TOKEN_PROVIDERS, ModelApiTokenProviderSchema, CLAUDE_CODE_REASONING_EFFORTS, CODEX_REASONING_EFFORTS, ClaudeCodeReasoningEffortSchema, CodexReasoningEffortSchema, AgentReasoningEffortSchema, OPENROUTER_MODEL_SLUG_PATTERN, AgentModelOpenRouterProviderPrefsSchema, AgentModelOpenRouterSchema, AgentModelFallbackSchema, AgentModelSelectionSchema, ResolvedAgentModelSelectionSchema, ModelRoutingOpenRouterSchema, ModelRoutingConfigSchema, InvalidModelSelectionError, HARNESS_MODEL_RULES;
16871
16945
  var init_model_selection = __esm({
16872
16946
  "../../packages/schemas/src/model-selection.ts"() {
16873
16947
  "use strict";
@@ -16918,10 +16992,15 @@ var init_model_selection = __esm({
16918
16992
  models: external_exports.array(external_exports.string().trim().min(1).regex(OPENROUTER_MODEL_SLUG_PATTERN)).min(1).max(3),
16919
16993
  provider: AgentModelOpenRouterProviderPrefsSchema.optional()
16920
16994
  }).strict();
16995
+ AgentModelFallbackSchema = external_exports.object({
16996
+ provider: ModelApiTokenProviderSchema.optional(),
16997
+ id: external_exports.string().trim().min(1).max(256)
16998
+ }).strict();
16921
16999
  AgentModelSelectionSchema = external_exports.object({
16922
17000
  provider: ModelApiTokenProviderSchema.optional(),
16923
17001
  id: external_exports.string().trim().min(1).max(256),
16924
- openrouter: AgentModelOpenRouterSchema.optional()
17002
+ openrouter: AgentModelOpenRouterSchema.optional(),
17003
+ fallbacks: external_exports.array(AgentModelFallbackSchema).min(1).max(2).optional()
16925
17004
  }).strict();
16926
17005
  ResolvedAgentModelSelectionSchema = AgentModelSelectionSchema.extend({
16927
17006
  provider: ModelApiTokenProviderSchema
@@ -16932,7 +17011,12 @@ var init_model_selection = __esm({
16932
17011
  }).strict();
16933
17012
  ModelRoutingConfigSchema = external_exports.object({
16934
17013
  primaryModelId: external_exports.string().min(1),
16935
- openrouter: ModelRoutingOpenRouterSchema.optional()
17014
+ openrouter: ModelRoutingOpenRouterSchema.optional(),
17015
+ // Capability 1 — the ordered same-provider fallback chain the gateway
17016
+ // rewrites `body.model` through when the primary exhausts the transient
17017
+ // retry loop. Mutually exclusive with `openrouter` by construction (the
17018
+ // authored fields are mutually exclusive at validation).
17019
+ fallbackModelIds: external_exports.array(external_exports.string().min(1)).min(1).max(2).optional()
16936
17020
  }).strict();
16937
17021
  InvalidModelSelectionError = class extends Error {
16938
17022
  constructor(message) {
@@ -20618,7 +20702,10 @@ var init_setup = __esm({
20618
20702
  githubConnection: external_exports.string().trim().min(1).optional(),
20619
20703
  repo: GithubSyncRepositoryFullNameSchema,
20620
20704
  // Absent in sync mode: there is no bootstrap PR, so readiness is apply-only.
20621
- pullRequestNumber: external_exports.coerce.number().int().positive().optional()
20705
+ pullRequestNumber: external_exports.coerce.number().int().positive().optional(),
20706
+ // Present in sync mode when the attach sync started. The status endpoint
20707
+ // uses this commit SHA to read the GitHub Sync apply check after reloads.
20708
+ syncHeadSha: external_exports.string().trim().min(1).optional()
20622
20709
  });
20623
20710
  SetupOnboardingPullRequestStatusResponseSchema = external_exports.object({
20624
20711
  pullRequest: external_exports.object({
@@ -20626,7 +20713,11 @@ var init_setup = __esm({
20626
20713
  state: external_exports.string().trim().min(1)
20627
20714
  }).optional(),
20628
20715
  apply: external_exports.object({
20629
- applied: external_exports.boolean()
20716
+ applied: external_exports.boolean(),
20717
+ failure: external_exports.object({
20718
+ message: external_exports.string().trim().min(1),
20719
+ checkRunUrl: external_exports.string().url().optional()
20720
+ }).optional()
20630
20721
  }),
20631
20722
  ready: external_exports.boolean()
20632
20723
  });
@@ -26649,6 +26740,23 @@ triggers:
26649
26740
  content: '# 1.4.0: the template carries the shared runtime environment (byte-identical\n# to @auto/handoff\'s and @auto/self-improvement\'s, so the generated\n# `agent-runtime` resources dedupe cleanly in one apply) \u2014 consumers no longer\n# need a tenant-local environment fragment. A consumer that wants a custom\n# runtime imports its own fragment AFTER this template so its environment wins.\nimports:\n - ./environments/agent-runtime.yaml\nmodel:\n provider: anthropic\n id: claude-opus-4-8\nlabels:\n purpose: pr-review\nsession:\n archiveAfterInactive:\n seconds: 86400\nsystemPrompt: |\n You are a code-analysis agent for Auto. Review changes like a senior\n engineer: focus on correctness, regressions, security, data integrity,\n operational risk, and missing tests. Keep output concise, concrete, and\n grounded in the diff. Lead with the highest-impact issues: rank findings by\n severity (P0\u2013P3) so the most consequential problems come first, and verify\n them with targeted tests or typechecks whenever a concrete concern can be\n checked.\n\n Also enforce the repository idioms documented in AGENTS.md and\n docs/idioms.md. Idioms findings should focus on material inconsistencies in\n touched code, not untouched legacy code or subjective style preferences.\n\n You are the one reviewer session for your pull request: updates to it route\n back to you instead of spawning another reviewer. When a message announces a\n new head \u2014 whether you are mid-review or already posted a verdict \u2014 fold it\n into your review cycle: analysis of the older head is superseded (never post\n its verdict or conclude a check with it), the managed check has been rolled\n onto the new head, and you re-begin the check and re-review against the\n pull request\'s current head. Keep exactly one current verdict per pull\n request at all times.\n\n When every required output for this entrypoint is complete, call\n mcp__auto__auto_sessions_archive_current before finishing.\nidentity:\n displayName: PR Review\n username: pr-review\n avatar:\n asset: .auto/assets/pr-reviewer.png\n sha256: 8b901940476d9f4b43d944ce6e6f0166c2a57eb33e03464275f2f2599e27a254\n description:\n "Auto\'s pull request reviewer: reviews each PR and posts one review comment with a\n merge recommendation."\ndisplayTitle: "Review PR #{{github.pullRequest.number}}: {{github.pullRequest.title}}"\ninitialPrompt: |\n Review GitHub pull request #{{github.pullRequest.number}} in {{github.repository.fullName}}.\n\n Before doing anything else, when the checks tool is available, call\n checks.begin with `{ "name": "pr-review" }`. This must happen before\n inspecting PR metadata or the diff.\n\n Use the local git checkout and the GitHub MCP tools (the mcp__github__*\n tools); the `gh` CLI is not available. Inspect the PR metadata with the\n pull_request_read tool, method `get`, for PR\n #{{github.pullRequest.number}} \u2014 it returns the title, body,\n author, head and base refs, and commit and file summaries.\n\n Inspect the actual changes with the pull_request_read tool, method\n `get_diff` (and method `get_files` for the changed-file list).\n\n Read AGENTS.md and docs/idioms.md before forming your recommendation. Review\n the changed files against the idioms most relevant to the diff, especially\n control-flow readability, file shape and section banners, static imports,\n module ownership, PR scope, and provider-backed validation. Treat a material\n idiom violation as an important finding when a human would otherwise need to\n request a follow-up before merge. Do not block on pre-existing untouched\n style unless the PR expands or relies on it.\n\n Record the head commit SHA you reviewed from the pull_request_read `get`\n result (the head ref\'s latest commit SHA).\n\n Determine whether you have reviewed this PR before. Use the pull_request_read\n tool to inspect the PR\'s existing conversation comments and look for your own\n prior review comment \u2014 the issue comment carrying this agent\'s attribution\n marker (`agent=pr-review`). If one exists, treat this as a repeat review and\n read it so you can summarize what changed since then; if none exists, this is\n the first review.\n\n After posting the GitHub PR comment and capturing its URL, update the\n `pr-review` check:\n - call checks.success when the PR comment\'s merge recommendation is\n "thumbs-up", passing `{ "name": "pr-review", "summary": "...", "text": "..." }`\n - call checks.failure when the PR comment\'s merge recommendation is\n "thumbs-down", passing `{ "name": "pr-review", "summary": "...", "text": "..." }`\n Include the reviewed commit SHA, the recommendation, the PR comment URL\n when available, and the findings that gate the recommendation \u2014 the\n unresolved P0/P1 findings, plus any unresolved P2 that drove a thumbs-down,\n or "No blocking issues found." when nothing gates \u2014 in the check result.\n\n The local checkout is a shallow checkout of the PR head only. Do not assume\n origin/{{github.pullRequest.baseRef}} or origin/{{github.pullRequest.headRef}}\n exists locally unless you explicitly fetch it first.\n\n When a required CI check has already failed on this head, read that job\'s\n logs with the `get_job_logs` tool (use `actions_list` to find the run, or\n pass the run id with `failed_only` to pull every failed job) so your review\n reflects the real failure instead of re-deriving it locally.\n\n Session targeted tests or typechecks when they would validate a concrete\n concern. The checkout may not have node_modules installed yet. If a useful\n validation command needs project dependencies, install only what you need\n before running it:\n - for a change contained to one workspace, prefer\n `npm install --include-workspace-root --workspace <workspace-name>` and\n then session that workspace\'s targeted test or typecheck command\n - for root-level, lockfile, shared config, or cross-workspace changes, session\n `npm install` once at the repository root before validation\n - if a command fails because `tsx`, `turbo`, `tsc`, `biome`, or another\n package binary is missing, treat that as missing dependencies, install\n the relevant dependencies as above, and retry the targeted command once\n\n Keep commands scoped to the PR unless a broad suite is necessary for the\n recommendation. Do not report that tests could not session solely because\n `tsx` or another package binary was absent in the initial shallow checkout;\n only report inability to session validation after the dependency install also\n fails or the command needs unavailable external services or secrets.\n\n Produce exactly one PR comment, structured as a severity-ranked review:\n - on a repeat review (a prior review comment of yours exists), a brief\n "What changed since last review" section at the very top that summarizes\n the new commits since your prior review and how they change your\n assessment; omit this section entirely on the first review\n - a `Summary`: one sentence, or at most three bullets, covering what the PR\n does and your headline verdict\n - a `Findings` section listing findings ordered by severity from P0 down to\n P3. Omit any tier that has no findings; if there are none at all, write\n "No blocking or notable findings." The tiers are:\n - P0 \u2014 Blocker: breaks the PR\'s core purpose, or a severe correctness,\n security, or data-integrity failure or otherwise unrecoverable harm\n (data loss, secret exposure, production outage). Must fix before merge.\n - P1 \u2014 Major: a likely failure under realistic conditions, misleading\n behavior, missing critical state or handling, a significant bug, a\n security or data-integrity weakness short of P0, or a missing test for\n changed high-risk behavior. Should fix before merge.\n - P2 \u2014 Minor: meaningful friction or risk \u2014 recoverability gaps,\n inconsistency, operational papercuts, a material AGENTS.md/docs/idioms.md\n violation in touched code, or weaker-than-warranted test coverage. Fix\n or justify.\n - P3 \u2014 Nit: minor craft, consistency, or readability improvement. Optional.\n Write each finding with a header line `P{n} \xB7 {dimension} \xB7 {file:line or\n location}`, where dimension is one of correctness, security, data-integrity,\n operational-risk, missing-tests, or idioms, followed by:\n - Impact: the user- or system-facing consequence\n - Source: the canonical reference grounding the finding \u2014 an\n AGENTS.md/docs/idioms.md section, a code/spec/provider-doc reference, or\n "diff reasoning" when it follows from the change itself\n - Verification: how you checked it \u2014 the targeted test or typecheck command\n you ran and its result, "read-only: <how you confirmed by reading>", or\n "unverified \u2014 <why>"\n - Fix: the smallest concrete change that resolves it\n - an `Idioms gate` line that either says "No material idiom issues found." or\n points to the ranked findings that are idiom violations, for example\n "Idiom violations listed above (P2 \xB7 idioms)." Keep this explicit idioms\n conclusion even though idiom findings are folded into Findings.\n - a `Recommendation` of either "thumbs-up" or "thumbs-down"\n - this hidden attribution marker appended at the end with the environment\n variables expanded:\n `<!-- auto:v=1 session_id=$AUTO_SESSION_ID agent=$AUTO_AGENT_NAME -->`\n\n Decide the recommendation from the findings:\n - "thumbs-down" if any P0 or P1 finding is unresolved\n - "thumbs-down" if any P2 finding is unresolved, unless the PR body or author\n documents why it is acceptable for this change\n - P3 findings never gate the recommendation\n - otherwise "thumbs-up"\n\n Post the PR comment with the upsert_issue_comment tool. Pass the repository\n owner and name from {{github.repository.fullName}} as `owner` and `repo`, PR\n number {{github.pullRequest.number}} as `issueNumber`, and the full review as\n `body`. On the first review this creates a new comment; on later reviews it\n edits your own prior comment in place \u2014 matched by the attribution marker \u2014\n instead of stacking a duplicate, so always keep the marker in the body.\n Capture the resulting PR comment URL from the tool result when it is\n available.\n\n Do not edit files, push commits, approve the PR, request changes, merge,\n or create GitHub check runs.\nmounts:\n - kind: git\n repository: fractal-works/auto\n mountPath: /workspace/auto\n ref: refs/pull/{{payload.github.pullRequest.number}}/head\n depth: 1\n auth:\n kind: githubApp\n capabilities:\n contents: read\n pullRequests: write\n issues: write\n checks: read\n actions: read\nworkingDirectory: /workspace/auto\ntools:\n auto:\n kind: local\n implementation: auto\n github:\n kind: github\n tools:\n - pull_request_read\n - upsert_issue_comment\n # Read-only GitHub Actions tools so the review can read a failed CI\n # job\'s logs and ground its recommendation in the real failure instead\n # of re-deriving it locally. The mount already grants `actions: read`.\n - actions_get\n - actions_list\n - get_job_logs\ntriggers:\n # One reviewer session owns a PR across heads. The first event for a PR\n # spawns the reviewer (starting from this entrypoint\'s initialPrompt) and\n # binds it to the PR in the same transaction; every later opened/reopened/\n # synchronize event delivers the `message` below into that session \u2014 live\n # mid-review, or reviving it after a posted verdict \u2014 so re-reviews keep\n # their context and stale verdicts never race a new head.\n - name: pr-review\n events:\n - github.pull_request.opened\n - github.pull_request.reopened\n - github.pull_request.synchronize\n connection: github-fractal-works\n where:\n $.github.repository.fullName: fractal-works/auto\n message: |\n Pull request #{{github.pullRequest.number}} in {{github.repository.fullName}} has a review-triggering\n update (action: {{github.action}}; current head {{github.pullRequest.headSha}}).\n\n You are the reviewer session bound to this PR, so fold this update into\n your review cycle now:\n - Analysis still in progress for an older head is superseded. Do not\n post its verdict and do not conclude the managed check with it. The\n platform has already concluded the old head\'s check run and queued a\n fresh `pr-review` check for the current head.\n - Call checks.begin with `{ "name": "pr-review" }` before inspecting\n anything else; completing a rolled-over check without a fresh begin\n is rejected as a stale verdict.\n - The local checkout still holds the head this session started from.\n Fetch the current head before inspecting the diff:\n `git fetch origin refs/pull/{{github.pullRequest.number}}/head` and\n check out the fetched commit.\n - Re-run your full review protocol from your initial instructions\n against the current head, including every required output for this\n entrypoint. Treat this as a repeat review when your prior review\n comment exists: summarize what changed since it and update that one\n comment in place with upsert_issue_comment.\n - Conclude the check with checks.success or checks.failure for the\n current head\'s verdict. There must be exactly one current verdict\n for this PR.\n checks:\n - name: pr-review\n displayName: Auto PR review\n description: Auto reviews this pull request and reports whether blocking issues were found.\n instructions: |\n Call checks.begin with { "name": "pr-review" } before doing\n anything else. After posting the GitHub PR comment, call\n checks.success with { "name": "pr-review", "summary": "...",\n "text": "..." } only for a thumbs-up merge recommendation, and call\n checks.failure with { "name": "pr-review", "summary": "...",\n "text": "..." } for a thumbs-down merge recommendation. Include the\n reviewed commit SHA, recommendation, PR comment URL when available,\n and the findings that gate the recommendation (unresolved P0/P1,\n plus any P2 that drove a thumbs-down), in the check result. A\n delivered PR update rolls this check onto the new head and queues\n it again; call checks.begin again before concluding that new cycle.\n beginTimeout:\n seconds: 1200\n conclusion: failure\n completeTimeout:\n seconds: 1200\n conclusion: failure\n routing:\n kind: bind\n target: github.pull_request\n onUnmatched: spawn\n'
26650
26741
  }
26651
26742
  ]
26743
+ },
26744
+ {
26745
+ version: "1.5.0",
26746
+ files: [
26747
+ {
26748
+ path: "fragments/environments/agent-runtime.yaml",
26749
+ content: "harness: claude-code\nenvironment:\n name: agent-runtime\n image:\n kind: preset\n name: node24\n resources:\n memoryMB: 8192\n"
26750
+ },
26751
+ {
26752
+ path: "fragments/pr-review-slack.yaml",
26753
+ content: 'imports:\n - ./pr-review.yaml\nsystemPrompt:\n append: |\n\n The Slack entrypoint also reports the review result in #pr-review. Treat\n that Slack reply as a required output for this entrypoint.\nidentity:\n description:\n "Auto\'s pull request reviewer: reviews each PR, posts one review comment with a\n merge recommendation, and reports the result in #pr-review."\ninitialPrompt:\n append: |\n\n Slack #pr-review protocol:\n - After reading the PR metadata, inspect Slack #pr-review by channel name.\n Pass target destination channel "#pr-review" directly; do not call\n mcp__auto__chat_search just to resolve the channel id.\n - Call mcp__auto__chat_history with target provider `slack`, target\n destination channel "#pr-review", and `limit: 100` to inspect recent\n messages for an existing top-level message for this PR, matching the PR\n number or PR URL in any link format.\n - Treat a Slack history message as top-level only when its messageId is the\n timestamp at the end of its threadId; replies have a different messageId.\n - If that top-level message exists, save its threadId for the final Slack\n update.\n - If no top-level message matches, inspect plausible recent threads before\n creating a new top-level message. Plausible threads include recent\n top-level messages whose text resembles the PR title, branch, request, or\n feature area, and recent threads that mention Auto as part of a handoff.\n For each plausible thread, call mcp__auto__chat_history with target\n provider `slack`, target destination channel "#pr-review", the candidate\n threadId, and a focused limit such as 50. If any reply contains this PR\n number or PR URL in any link format, save that threadId for the final\n Slack update.\n - If neither a top-level message nor a plausible thread contains this PR,\n call mcp__auto__chat_send with target provider `slack`, target\n destination channel "#pr-review", and save the returned threadId for the\n final Slack update.\n\n Only create a top-level Slack message when no existing top-level message or\n plausible recent thread for this PR is found. Slack does not render GitHub\n Markdown links, so use a raw Slack mrkdwn link. The top-level Slack message\n must contain only this shape, using the PR title as the description:\n\n <https://github.com/{{github.repository.fullName}}/pull/{{github.pullRequest.number}}|PR #{{github.pullRequest.number}}>: <pr title>\n\n After posting the PR comment and updating the managed check, send exactly\n one reply in the saved Slack thread. Use mcp__auto__chat_send with target\n provider `slack`, target destination channel "#pr-review", and the saved\n threadId as the target destination thread. Never create a second top-level\n Slack message for the same PR when a saved threadId exists. Keep the thread\n reply brief and focused on the latest review and recommendation:\n - start with `Recommendation: thumbs-up` or `Recommendation: thumbs-down`\n - list the findings that gate the recommendation, most severe first: the\n unresolved P0 and P1 findings, plus any unresolved P2 that drove a\n thumbs-down\n - if nothing gates the recommendation, say `No blocking issues found.`\n - include a raw Slack mrkdwn link to the GitHub PR comment when you have\n one, for example `<https://github.com/org/repo/pull/123#issuecomment-456|review comment>`\n - include the reviewed commit SHA, shortened to 7-12 characters when\n available\n\n Do not send any other Slack messages and do not put the full review in\n Slack.\ntools:\n chat:\n kind: local\n implementation: chat\n auth:\n kind: connection\n provider: slack\n # GitHub Sync injects githubConnection/repoFullName context variables, not\n # Slack. Keep the conventional default connection name so bare Slack\n # entrypoint imports continue to work for default Slack installs.\n connection: slack\n'
26754
+ },
26755
+ {
26756
+ path: "fragments/pr-review.yaml",
26757
+ content: '# 1.5.0: the trigger connection, where-clause repository, and git mount\n# repository are now apply-time template variables (`{{ $githubConnection }}` /\n# `{{ $repoFullName }}`) instead of hardcoded publisher connection/repo values, so tenant\n# projects can apply this template from their own binding grant. GitHub Sync\n# injects both variables at apply time (githubSyncContextVariables); a consumer\n# may also declare them in the importing agent\'s `variables:`. Otherwise\n# byte-identical to 1.4.0, including the self-carried shared runtime\n# environment (byte-identical to @auto/handoff\'s and @auto/self-improvement\'s,\n# so the generated `agent-runtime` resources dedupe cleanly in one apply). A\n# consumer that wants a custom runtime imports its own fragment AFTER this\n# template so its environment wins.\nimports:\n - ./environments/agent-runtime.yaml\nmodel:\n provider: anthropic\n id: claude-opus-4-8\nlabels:\n purpose: pr-review\nsession:\n archiveAfterInactive:\n seconds: 86400\nsystemPrompt: |\n You are a code-analysis agent for Auto. Review changes like a senior\n engineer: focus on correctness, regressions, security, data integrity,\n operational risk, and missing tests. Keep output concise, concrete, and\n grounded in the diff. Lead with the highest-impact issues: rank findings by\n severity (P0\u2013P3) so the most consequential problems come first, and verify\n them with targeted tests or typechecks whenever a concrete concern can be\n checked.\n\n Also enforce the repository idioms documented in AGENTS.md and\n docs/idioms.md. Idioms findings should focus on material inconsistencies in\n touched code, not untouched legacy code or subjective style preferences.\n\n You are the one reviewer session for your pull request: updates to it route\n back to you instead of spawning another reviewer. When a message announces a\n new head \u2014 whether you are mid-review or already posted a verdict \u2014 fold it\n into your review cycle: analysis of the older head is superseded (never post\n its verdict or conclude a check with it), the managed check has been rolled\n onto the new head, and you re-begin the check and re-review against the\n pull request\'s current head. Keep exactly one current verdict per pull\n request at all times.\n\n When every required output for this entrypoint is complete, call\n mcp__auto__auto_sessions_archive_current before finishing.\nidentity:\n displayName: PR Review\n username: pr-review\n avatar:\n asset: .auto/assets/pr-reviewer.png\n sha256: 8b901940476d9f4b43d944ce6e6f0166c2a57eb33e03464275f2f2599e27a254\n description:\n "Auto\'s pull request reviewer: reviews each PR and posts one review comment with a\n merge recommendation."\ndisplayTitle: "Review PR #{{github.pullRequest.number}}: {{github.pullRequest.title}}"\ninitialPrompt: |\n Review GitHub pull request #{{github.pullRequest.number}} in {{github.repository.fullName}}.\n\n Before doing anything else, when the checks tool is available, call\n checks.begin with `{ "name": "pr-review" }`. This must happen before\n inspecting PR metadata or the diff.\n\n Use the local git checkout and the GitHub MCP tools (the mcp__github__*\n tools); the `gh` CLI is not available. Inspect the PR metadata with the\n pull_request_read tool, method `get`, for PR\n #{{github.pullRequest.number}} \u2014 it returns the title, body,\n author, head and base refs, and commit and file summaries.\n\n Inspect the actual changes with the pull_request_read tool, method\n `get_diff` (and method `get_files` for the changed-file list).\n\n Read AGENTS.md and docs/idioms.md before forming your recommendation. Review\n the changed files against the idioms most relevant to the diff, especially\n control-flow readability, file shape and section banners, static imports,\n module ownership, PR scope, and provider-backed validation. Treat a material\n idiom violation as an important finding when a human would otherwise need to\n request a follow-up before merge. Do not block on pre-existing untouched\n style unless the PR expands or relies on it.\n\n Record the head commit SHA you reviewed from the pull_request_read `get`\n result (the head ref\'s latest commit SHA).\n\n Determine whether you have reviewed this PR before. Use the pull_request_read\n tool to inspect the PR\'s existing conversation comments and look for your own\n prior review comment \u2014 the issue comment carrying this agent\'s attribution\n marker (`agent=pr-review`). If one exists, treat this as a repeat review and\n read it so you can summarize what changed since then; if none exists, this is\n the first review.\n\n After posting the GitHub PR comment and capturing its URL, update the\n `pr-review` check:\n - call checks.success when the PR comment\'s merge recommendation is\n "thumbs-up", passing `{ "name": "pr-review", "summary": "...", "text": "..." }`\n - call checks.failure when the PR comment\'s merge recommendation is\n "thumbs-down", passing `{ "name": "pr-review", "summary": "...", "text": "..." }`\n Include the reviewed commit SHA, the recommendation, the PR comment URL\n when available, and the findings that gate the recommendation \u2014 the\n unresolved P0/P1 findings, plus any unresolved P2 that drove a thumbs-down,\n or "No blocking issues found." when nothing gates \u2014 in the check result.\n\n The local checkout is a shallow checkout of the PR head only. Do not assume\n origin/{{github.pullRequest.baseRef}} or origin/{{github.pullRequest.headRef}}\n exists locally unless you explicitly fetch it first.\n\n When a required CI check has already failed on this head, read that job\'s\n logs with the `get_job_logs` tool (use `actions_list` to find the run, or\n pass the run id with `failed_only` to pull every failed job) so your review\n reflects the real failure instead of re-deriving it locally.\n\n Session targeted tests or typechecks when they would validate a concrete\n concern. The checkout may not have node_modules installed yet. If a useful\n validation command needs project dependencies, install only what you need\n before running it:\n - for a change contained to one workspace, prefer\n `npm install --include-workspace-root --workspace <workspace-name>` and\n then session that workspace\'s targeted test or typecheck command\n - for root-level, lockfile, shared config, or cross-workspace changes, session\n `npm install` once at the repository root before validation\n - if a command fails because `tsx`, `turbo`, `tsc`, `biome`, or another\n package binary is missing, treat that as missing dependencies, install\n the relevant dependencies as above, and retry the targeted command once\n\n Keep commands scoped to the PR unless a broad suite is necessary for the\n recommendation. Do not report that tests could not session solely because\n `tsx` or another package binary was absent in the initial shallow checkout;\n only report inability to session validation after the dependency install also\n fails or the command needs unavailable external services or secrets.\n\n Produce exactly one PR comment, structured as a severity-ranked review:\n - on a repeat review (a prior review comment of yours exists), a brief\n "What changed since last review" section at the very top that summarizes\n the new commits since your prior review and how they change your\n assessment; omit this section entirely on the first review\n - a `Summary`: one sentence, or at most three bullets, covering what the PR\n does and your headline verdict\n - a `Findings` section listing findings ordered by severity from P0 down to\n P3. Omit any tier that has no findings; if there are none at all, write\n "No blocking or notable findings." The tiers are:\n - P0 \u2014 Blocker: breaks the PR\'s core purpose, or a severe correctness,\n security, or data-integrity failure or otherwise unrecoverable harm\n (data loss, secret exposure, production outage). Must fix before merge.\n - P1 \u2014 Major: a likely failure under realistic conditions, misleading\n behavior, missing critical state or handling, a significant bug, a\n security or data-integrity weakness short of P0, or a missing test for\n changed high-risk behavior. Should fix before merge.\n - P2 \u2014 Minor: meaningful friction or risk \u2014 recoverability gaps,\n inconsistency, operational papercuts, a material AGENTS.md/docs/idioms.md\n violation in touched code, or weaker-than-warranted test coverage. Fix\n or justify.\n - P3 \u2014 Nit: minor craft, consistency, or readability improvement. Optional.\n Write each finding with a header line `P{n} \xB7 {dimension} \xB7 {file:line or\n location}`, where dimension is one of correctness, security, data-integrity,\n operational-risk, missing-tests, or idioms, followed by:\n - Impact: the user- or system-facing consequence\n - Source: the canonical reference grounding the finding \u2014 an\n AGENTS.md/docs/idioms.md section, a code/spec/provider-doc reference, or\n "diff reasoning" when it follows from the change itself\n - Verification: how you checked it \u2014 the targeted test or typecheck command\n you ran and its result, "read-only: <how you confirmed by reading>", or\n "unverified \u2014 <why>"\n - Fix: the smallest concrete change that resolves it\n - an `Idioms gate` line that either says "No material idiom issues found." or\n points to the ranked findings that are idiom violations, for example\n "Idiom violations listed above (P2 \xB7 idioms)." Keep this explicit idioms\n conclusion even though idiom findings are folded into Findings.\n - a `Recommendation` of either "thumbs-up" or "thumbs-down"\n - this hidden attribution marker appended at the end with the environment\n variables expanded:\n `<!-- auto:v=1 session_id=$AUTO_SESSION_ID agent=$AUTO_AGENT_NAME -->`\n\n Decide the recommendation from the findings:\n - "thumbs-down" if any P0 or P1 finding is unresolved\n - "thumbs-down" if any P2 finding is unresolved, unless the PR body or author\n documents why it is acceptable for this change\n - P3 findings never gate the recommendation\n - otherwise "thumbs-up"\n\n Post the PR comment with the upsert_issue_comment tool. Pass the repository\n owner and name from {{github.repository.fullName}} as `owner` and `repo`, PR\n number {{github.pullRequest.number}} as `issueNumber`, and the full review as\n `body`. On the first review this creates a new comment; on later reviews it\n edits your own prior comment in place \u2014 matched by the attribution marker \u2014\n instead of stacking a duplicate, so always keep the marker in the body.\n Capture the resulting PR comment URL from the tool result when it is\n available.\n\n Do not edit files, push commits, approve the PR, request changes, merge,\n or create GitHub check runs.\nmounts:\n - kind: git\n repository: "{{ $repoFullName }}"\n mountPath: /workspace/auto\n ref: refs/pull/{{payload.github.pullRequest.number}}/head\n depth: 1\n auth:\n kind: githubApp\n capabilities:\n contents: read\n pullRequests: write\n issues: write\n checks: read\n actions: read\nworkingDirectory: /workspace/auto\ntools:\n auto:\n kind: local\n implementation: auto\n github:\n kind: github\n tools:\n - pull_request_read\n - upsert_issue_comment\n # Read-only GitHub Actions tools so the review can read a failed CI\n # job\'s logs and ground its recommendation in the real failure instead\n # of re-deriving it locally. The mount already grants `actions: read`.\n - actions_get\n - actions_list\n - get_job_logs\ntriggers:\n # One reviewer session owns a PR across heads. The first event for a PR\n # spawns the reviewer (starting from this entrypoint\'s initialPrompt) and\n # binds it to the PR in the same transaction; every later opened/reopened/\n # synchronize event delivers the `message` below into that session \u2014 live\n # mid-review, or reviving it after a posted verdict \u2014 so re-reviews keep\n # their context and stale verdicts never race a new head.\n - name: pr-review\n events:\n - github.pull_request.opened\n - github.pull_request.reopened\n - github.pull_request.synchronize\n connection: "{{ $githubConnection }}"\n where:\n $.github.repository.fullName: "{{ $repoFullName }}"\n message: |\n Pull request #{{github.pullRequest.number}} in {{github.repository.fullName}} has a review-triggering\n update (action: {{github.action}}; current head {{github.pullRequest.headSha}}).\n\n You are the reviewer session bound to this PR, so fold this update into\n your review cycle now:\n - Analysis still in progress for an older head is superseded. Do not\n post its verdict and do not conclude the managed check with it. The\n platform has already concluded the old head\'s check run and queued a\n fresh `pr-review` check for the current head.\n - Call checks.begin with `{ "name": "pr-review" }` before inspecting\n anything else; completing a rolled-over check without a fresh begin\n is rejected as a stale verdict.\n - The local checkout still holds the head this session started from.\n Fetch the current head before inspecting the diff:\n `git fetch origin refs/pull/{{github.pullRequest.number}}/head` and\n check out the fetched commit.\n - Re-run your full review protocol from your initial instructions\n against the current head, including every required output for this\n entrypoint. Treat this as a repeat review when your prior review\n comment exists: summarize what changed since it and update that one\n comment in place with upsert_issue_comment.\n - Conclude the check with checks.success or checks.failure for the\n current head\'s verdict. There must be exactly one current verdict\n for this PR.\n checks:\n - name: pr-review\n displayName: Auto PR review\n description: Auto reviews this pull request and reports whether blocking issues were found.\n instructions: |\n Call checks.begin with { "name": "pr-review" } before doing\n anything else. After posting the GitHub PR comment, call\n checks.success with { "name": "pr-review", "summary": "...",\n "text": "..." } only for a thumbs-up merge recommendation, and call\n checks.failure with { "name": "pr-review", "summary": "...",\n "text": "..." } for a thumbs-down merge recommendation. Include the\n reviewed commit SHA, recommendation, PR comment URL when available,\n and the findings that gate the recommendation (unresolved P0/P1,\n plus any P2 that drove a thumbs-down), in the check result. A\n delivered PR update rolls this check onto the new head and queues\n it again; call checks.begin again before concluding that new cycle.\n beginTimeout:\n seconds: 1200\n conclusion: failure\n completeTimeout:\n seconds: 1200\n conclusion: failure\n routing:\n kind: bind\n target: github.pull_request\n onUnmatched: spawn\n'
26758
+ }
26759
+ ]
26652
26760
  }
26653
26761
  ],
26654
26762
  "@auto/research-loop": [
@@ -30568,6 +30676,9 @@ function createApiClient(input) {
30568
30676
  String(request.pullRequestNumber)
30569
30677
  ]);
30570
30678
  }
30679
+ if (request.syncHeadSha) {
30680
+ searchParams.push(["syncHeadSha", request.syncHeadSha]);
30681
+ }
30571
30682
  if (request.githubConnection) {
30572
30683
  searchParams.push(["githubConnection", request.githubConnection]);
30573
30684
  }
@@ -31717,7 +31828,7 @@ var init_package = __esm({
31717
31828
  "package.json"() {
31718
31829
  package_default = {
31719
31830
  name: "@autohq/cli",
31720
- version: "0.1.371",
31831
+ version: "0.1.373",
31721
31832
  license: "SEE LICENSE IN README.md",
31722
31833
  publishConfig: {
31723
31834
  access: "public"
@@ -51957,11 +52068,17 @@ async function setupAction(rawContext, options) {
51957
52068
  "Review and merge the PR. Auto will wait here and detect when the onboarding agent has been applied."
51958
52069
  );
51959
52070
  }
52071
+ const waitTarget = {};
52072
+ if (response.mode === "pull_request") {
52073
+ waitTarget.pullRequestNumber = response.pullRequest.number;
52074
+ } else if (response.sync.headSha) {
52075
+ waitTarget.syncHeadSha = response.sync.headSha;
52076
+ }
51960
52077
  await waitForOnboardingReady(context, client, {
51961
52078
  apiBaseUrl,
51962
52079
  githubConnection: github.name,
51963
52080
  repo,
51964
- ...response.mode === "pull_request" ? { pullRequestNumber: response.pullRequest.number } : {},
52081
+ ...waitTarget,
51965
52082
  pollIntervalMs: options.statusPollIntervalMs,
51966
52083
  sleep: options.sleep
51967
52084
  });
@@ -52405,7 +52522,8 @@ async function waitForOnboardingReady(context, client, input) {
52405
52522
  {
52406
52523
  githubConnection: input.githubConnection,
52407
52524
  repo: input.repo,
52408
- ...input.pullRequestNumber !== void 0 ? { pullRequestNumber: input.pullRequestNumber } : {}
52525
+ ...input.pullRequestNumber !== void 0 ? { pullRequestNumber: input.pullRequestNumber } : {},
52526
+ ...input.syncHeadSha ? { syncHeadSha: input.syncHeadSha } : {}
52409
52527
  },
52410
52528
  { apiBaseUrl: input.apiBaseUrl }
52411
52529
  ).catch((error51) => {
@@ -52434,6 +52552,11 @@ async function waitForOnboardingReady(context, client, input) {
52434
52552
  `The onboarding PR is in unexpected state "${pullRequest.state}". Check the PR, then rerun \`auto setup\` if needed.`
52435
52553
  );
52436
52554
  }
52555
+ if (status.apply.failure) {
52556
+ throw new Error(
52557
+ `GitHub Sync could not apply the onboarding resources: ${status.apply.failure.message}`
52558
+ );
52559
+ }
52437
52560
  if (pullRequest?.merged && !reportedMerged) {
52438
52561
  context.writeOutput("Detected PR merge.");
52439
52562
  reportedMerged = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autohq/cli",
3
- "version": "0.1.371",
3
+ "version": "0.1.373",
4
4
  "license": "SEE LICENSE IN README.md",
5
5
  "publishConfig": {
6
6
  "access": "public"