diff --git a/.agents/skills/import-upstream-pr/SKILL.md b/.agents/skills/import-upstream-pr/SKILL.md index 2430aa5cbad2f..68414b9548166 100644 --- a/.agents/skills/import-upstream-pr/SKILL.md +++ b/.agents/skills/import-upstream-pr/SKILL.md @@ -111,27 +111,24 @@ When accepted, rename the branch to `port/upstream/pr--`. 1. Immediately before delivery, fetch `origin/lastcode/main` again. If the port parent moved, rebase the imported commits and rerun affected validation. -2. Before the guarded push, require a clean worktree and record the local head, - destination base, and existing remote topic SHA (or its absence). Then push - in a clean environment so the pre-push `pnpm lastcode:ci:quick` gate sees - ordinary Git/SSH variables. Do not export `GIT_SSH_COMMAND` or inject an SSH - command through Git configuration around the push; those settings flow into - tests that intentionally control `GIT_SSH`. -3. If Quick CI passes but the idle SSH transport subsequently dies, do not - treat its generic success line as an exact-head receipt. Require the local - head to equal the recorded head, the worktree to remain clean, the fetched - destination base to equal the recorded base, and the remote topic SHA (or - absence) to remain unchanged. Only then retry that recorded head with - `--no-verify` and an exact `--force-with-lease` tied to the recorded remote - topic state. Otherwise rerun the guarded push and its hook. +2. Before publishing, run the independent **Run Quick CI** Project Action from + the clean exact port head. After it resumes, verify its receipt still matches + the head and destination base, then decide whether and what to push. The + pre-push hook consumes that receipt; ordinary command-line use falls back to + synchronous Quick CI. +3. If transport fails after the hook accepts the receipt, verify the local head, + worktree, destination base, and remote topic state before retrying. Reuse the + same receipt only for the unchanged commit and base; otherwise rerun the + action. 4. Open a PR targeting `lastcode/main` only when explicitly requested. Include the upstream PR and pinned head, observed state/date, import method, adaptations, rationale, validation, closure/review context, and published evidence. 5. For review and merge, follow `lastcode-pr` and `.agents/skills/_references/external-review-mechanics.md`: require a terminal - clean Codex result for the exact head, zero unresolved threads, and a full - `pnpm lastcode:ci` stamp for the exact head/current base. Merge only through + clean Codex result for the exact head, zero unresolved threads, and a + successful exact-head/base GitHub CI run and aggregate `CI Gate`. Use **Wait + for PR** during passive review or CI waits, and merge only through `pnpm lastcode:merge`. 6. Verify the merged commit on `origin/lastcode/main`. For a squash merge, compare stable patch IDs so provenance verification does not depend on the @@ -152,5 +149,5 @@ When accepted, rename the branch to `port/upstream/pr--`. Report the source PR state and pinned head, destination base and port head, import method and adaptations, validation and real-client evidence, PR/merge -state, exact-head review result, unresolved-thread count, full-CI stamp, and the +state, exact-head review result, unresolved-thread count, GitHub CI run, and the merged commit or remaining blocker. diff --git a/.agents/skills/import-upstream-pr/references/intake-and-evidence.md b/.agents/skills/import-upstream-pr/references/intake-and-evidence.md index 057a67ef5130e..e60608de7d017 100644 --- a/.agents/skills/import-upstream-pr/references/intake-and-evidence.md +++ b/.agents/skills/import-upstream-pr/references/intake-and-evidence.md @@ -143,8 +143,9 @@ Include: - focused and integrated validation; and - durable GitHub-hosted visual evidence for UI changes. -Before merge, refresh the PR snapshot and require the same exact head across the -clean Codex result, zero unresolved threads, full-CI stamp, and merge command. +Before merge, refresh the PR snapshot and require the same exact head and base +across the clean Codex result, zero unresolved threads, successful GitHub CI +run, aggregate `CI Gate`, and guarded merge command. After a squash merge, verify stable patch equivalence: diff --git a/.agents/skills/lastcode-pr/SKILL.md b/.agents/skills/lastcode-pr/SKILL.md index f64af0a6c458d..2b48174b72ad0 100644 --- a/.agents/skills/lastcode-pr/SKILL.md +++ b/.agents/skills/lastcode-pr/SKILL.md @@ -1,6 +1,6 @@ --- name: lastcode-pr -description: Deliver a LastCode-only change through its branch, local CI, Codex review, and guarded merge workflow. Use for Markover integration, LastCode identity or branding, personal conveniences, nightly checkpointing, ad-hoc releases, and any change intentionally not proposed to pingdotgg/t3code. Use upstream-fix instead when a general improvement should also be offered upstream. +description: Deliver a LastCode-only change through its branch, Quick CI, GitHub CI, Codex review, and guarded merge workflow. Use for Markover integration, LastCode identity or branding, personal conveniences, nightly checkpointing, ad-hoc releases, and any change intentionally not proposed to pingdotgg/t3code. Use upstream-fix instead when a general improvement should also be offered upstream. --- # LastCode PR @@ -30,7 +30,10 @@ and should be proposed upstream, switch to `upstream-fix`. for backend or automation behavior. 2. Run the smallest relevant tests, lint, and typecheck required by `AGENTS.md`. 3. Rebase onto the latest `origin/lastcode/main` before publishing. -4. Push the branch; the pre-push hook must pass `pnpm lastcode:ci:quick` locally. +4. Run the independent **Run Quick CI** Project Action. After it resumes with a + receipt for the exact clean head and workstream base, decide whether and what + to push. The pre-push hook consumes that receipt; ordinary command-line use + falls back to synchronous `pnpm lastcode:ci:quick`. 5. Open a PR targeting `lastcode/main` only when the user explicitly asks. An open PR targeting `lastcode/main` pauses promotion of a new nightly onto the @@ -54,9 +57,13 @@ current GitHub thread and review-query mechanics. `../_references/external-review-mechanics.md`. Do not merge until Codex gives an explicit clean result or every finding for the exact current head has a durable handled state, and no review thread remains unresolved. -4. Run `pnpm lastcode:ci` from a clean branch. Its full-CI stamp must match the - exact head and fetched `origin/lastcode/main` base. +4. Use the independent **Wait for PR** Project Action while exact-head GitHub CI + or Codex review is passive. It resumes only for an actionable result. Rebase, + fix, retry, or request another review only after inspecting that result. 5. Use `pnpm lastcode:merge`; do not bypass the guarded merge in the GitHub UI. + The wrapper independently revalidates a successful exact-head/base GitHub CI + run and aggregate `CI Gate`, a clean current PR, and an unchanged fetched + base immediately before its exact-head squash merge. 6. Verify the PR is merged and `origin/lastcode/main` contains the merge result. 7. If the work is tracked by Markover, confirm the GitHub terminal state and run the service-free command from the Markover checkout: @@ -71,6 +78,6 @@ external blocker requires the user. ## Handoff -Report the PR URL, merged commit or current head, focused and full validation, +Report the PR URL, merged commit or current head, focused and GitHub CI validation, Codex review result, unresolved-thread count, and Markover state when applicable. If no PR was requested, report the local branch and commit without publishing it. diff --git a/docs/lastcode/release.md b/docs/lastcode/release.md index 662240340fcfc..468f88cec8951 100644 --- a/docs/lastcode/release.md +++ b/docs/lastcode/release.md @@ -1,8 +1,8 @@ # LastCode Local Release Workflow -LastCode uses local validation and ad-hoc macOS releases. Ordinary branch CI -remains local. The one GitHub-hosted packaging path is manually dispatched for -an exact Intel checkpoint or revision; releases have no schedule. +LastCode uses a local waste-prevention gate, GitHub-hosted pull-request CI, and +ad-hoc macOS releases. The GitHub-hosted packaging path is manually dispatched +for an exact Intel checkpoint or revision; releases have no schedule. Nightly source tracking is documented separately in [Nightly Checkpoint Workflow](nightly-workflow.md). @@ -18,7 +18,7 @@ pnpm lastcode:ci:quick Quick CI is a local waste-prevention gate, not merge authority. It checks the exact branch diff for whitespace errors, repository formatting and lint, and workspace types. The implementing agent runs focused tests for changed behavior; -GitHub CI and the transitional full local gate retain comprehensive tests, +GitHub CI retains comprehensive tests, Electron setup, builds, Rust, native analysis, and release smoke coverage. Agents run the independent **Run Quick CI** Project Action before a push. A @@ -80,17 +80,12 @@ case at a time. This takes longer than the task-runner defaults but avoids cross-suite state leaks plus memory and CPU contention between the web, mobile, desktop, and server suites on the single local build machine. -Before merging a LastCode PR, run the full gate from a clean feature branch: - -```bash -pnpm lastcode:ci -``` - -The full PR gate fetches `origin/lastcode/main`, verifies that the tested head -contains that exact base commit, and runs formatting, linting, workspace -typechecks and tests, desktop build assertions, Rust tests, native static -analysis, and release smoke tests. Success writes a local stamp bound to both the -head commit and tested base. +The independent **Wait for PR** Project Action waits for both Codex review and +the exact GitHub pull-request workflow run. GitHub CI records the PR number, +head, base, and synthetic merge commit in the workflow run identity and exposes +one stable aggregate `CI Gate`. Head or base drift invalidates the result and +requires the agent to decide whether to rebase, republish, and request review +again. Merge the current ready PR with: @@ -98,10 +93,12 @@ Merge the current ready PR with: pnpm lastcode:merge ``` -The merge wrapper refuses dirty worktrees, unstamped commits, stale bases, draft -or conflicting PRs, and PRs that do not target `lastcode/main`. It squash-merges -with an exact-head guard, then requests an immediate checkpoint-daemon run. The -daemon publishes a new installable LastCode revision when no new upstream +The merge wrapper refuses dirty worktrees, missing or stale exact GitHub CI, +stale bases, draft or non-clean PRs, and PRs that do not target +`lastcode/main`. It fetches and checks the base again after reading CI, then +squash-merges with an exact-head guard and requests an immediate +checkpoint-daemon run. The daemon publishes a new installable LastCode revision +when no new upstream nightly is waiting. Failure to start the service is reported without lying about the already-completed GitHub merge; the hourly service run remains the repair path. The request never terminates a daemon run already in progress. diff --git a/scripts/lastcode-github-ci.test.ts b/scripts/lastcode-github-ci.test.ts index de9cd9a411592..f0bcfb4b614f4 100644 --- a/scripts/lastcode-github-ci.test.ts +++ b/scripts/lastcode-github-ci.test.ts @@ -7,6 +7,7 @@ import { githubCiRunTitle, githubCiRunsArgs, githubCiWorkflowArgs, + readGithubCi, testedMergeShaFromGithubCiRunTitle, type GithubCiEvaluationInput, } from "./lastcode-github-ci.ts"; @@ -68,6 +69,36 @@ describe("LastCode GitHub CI evidence", () => { ]); }); + it("reads workflow, rule, exact run, and aggregate job evidence through one shared path", () => { + const calls: string[] = []; + const responses = new Map([ + [githubCiWorkflowArgs("lastobelus/lastCode").join(" "), { state: "active" }], + [githubBranchRulesArgs("lastobelus/lastCode", "lastcode/main").join(" "), []], + [ + githubCiRunsArgs("lastobelus/lastCode", HEAD).join(" "), + { workflow_runs: input().workflowRuns }, + ], + [githubCiJobsArgs("lastobelus/lastCode", 456).join(" "), { jobs: input().jobs }], + ]); + const evidence = readGithubCi( + "lastobelus/lastCode", + { + number: 104, + headRefOid: HEAD, + baseRefOid: BASE, + baseRefName: "lastcode/main", + }, + (args: ReadonlyArray): T => { + const key = args.join(" "); + calls.push(key); + return responses.get(key) as T; + }, + ); + + expect(evidence).toMatchObject({ state: "satisfied", reason: "exact-run", runId: 456 }); + expect(calls).toEqual([...responses.keys()]); + }); + it("satisfies disabled, non-required hosted CI without a run", () => { for (const state of ["disabled_fork", "disabled_inactivity", "disabled_manually"]) { expect( diff --git a/scripts/lastcode-github-ci.ts b/scripts/lastcode-github-ci.ts index 12c97c7c91dfa..e696a576e4f3a 100644 --- a/scripts/lastcode-github-ci.ts +++ b/scripts/lastcode-github-ci.ts @@ -68,6 +68,23 @@ export interface GithubCiEvaluationInput { readonly jobs: ReadonlyArray | null; } +export interface GithubCiPullRequest { + readonly number: number; + readonly headRefOid: string; + readonly baseRefOid: string; + readonly baseRefName: string; +} + +export type RunGithubJson = (args: ReadonlyArray) => T; + +type WorkflowRunsResponse = { + readonly workflow_runs?: ReadonlyArray; +}; + +type WorkflowJobsResponse = { + readonly jobs?: ReadonlyArray; +}; + const runTimestamp = (run: GithubWorkflowRun): number => { const parsed = Date.parse(run.created_at ?? ""); return Number.isNaN(parsed) ? 0 : parsed; @@ -126,6 +143,39 @@ export function requiredGithubCiGate(branchRules: ReadonlyArray(githubCiWorkflowArgs(repository)); + const branchRules = runGithubJson>( + githubBranchRulesArgs(repository, pullRequest.baseRefName), + ); + const workflowRuns = + runGithubJson(githubCiRunsArgs(repository, pullRequest.headRefOid)) + .workflow_runs ?? []; + const evaluation = { + workflow, + branchRules, + pullRequestNumber: pullRequest.number, + headSha: pullRequest.headRefOid, + baseSha: pullRequest.baseRefOid, + workflowRuns, + jobs: null, + } as const; + const provisional = evaluateGithubCi(evaluation); + const completedSuccessRun = workflowRuns.find( + (run) => + run.id === provisional.runId && run.status === "completed" && run.conclusion === "success", + ); + if (!completedSuccessRun?.id) return provisional; + const jobs = + runGithubJson(githubCiJobsArgs(repository, completedSuccessRun.id)) + .jobs ?? []; + return evaluateGithubCi({ ...evaluation, jobs }); +} + const configurationFailure = (detail: string): GithubCiEvidence => ({ state: "failure", reason: "configuration", diff --git a/scripts/lastcode-merge.test.ts b/scripts/lastcode-merge.test.ts index 4afbe984e56d5..cf3217713f2b4 100644 --- a/scripts/lastcode-merge.test.ts +++ b/scripts/lastcode-merge.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vite-plus/test"; -import { validatePullRequestForMerge } from "./lastcode-merge.ts"; +import { validateGithubCiForMerge, validatePullRequestForMerge } from "./lastcode-merge.ts"; const mergeablePullRequest = { number: 12, @@ -11,16 +11,17 @@ const mergeablePullRequest = { baseRefName: "lastcode/main", baseRefOid: "base-sha", mergeable: "MERGEABLE", + mergeStateStatus: "CLEAN", } as const; describe("lastcode-merge", () => { - it("accepts an open LastCode PR at the stamped head", () => { + it("accepts an open, clean LastCode PR at the exact head and base", () => { expect(() => validatePullRequestForMerge(mergeablePullRequest, "head-sha", "base-sha"), ).not.toThrow(); }); - it("rejects drafts, stale heads, conflicts, and other base branches", () => { + it("rejects drafts, stale heads, non-clean merge state, and other base branches", () => { expect(() => validatePullRequestForMerge( { ...mergeablePullRequest, isDraft: true }, @@ -40,7 +41,14 @@ describe("lastcode-merge", () => { "head-sha", "base-sha", ), - ).toThrow("merge conflicts"); + ).toThrow("not cleanly mergeable"); + expect(() => + validatePullRequestForMerge( + { ...mergeablePullRequest, mergeStateStatus: "BEHIND" }, + "head-sha", + "base-sha", + ), + ).toThrow("not cleanly mergeable"); expect(() => validatePullRequestForMerge( { ...mergeablePullRequest, baseRefName: "main" }, @@ -49,4 +57,28 @@ describe("lastcode-merge", () => { ), ).toThrow("not 'lastcode/main'"); }); + + it("accepts only a successful exact GitHub CI run", () => { + expect(() => + validateGithubCiForMerge({ + state: "satisfied", + reason: "exact-run", + runId: 456, + testedMergeSha: "a".repeat(40), + }), + ).not.toThrow(); + expect(() => validateGithubCiForMerge({ state: "satisfied", reason: "not-expected" })).toThrow( + "not merge-ready", + ); + expect(() => + validateGithubCiForMerge({ state: "pending", reason: "run-in-progress", runId: 456 }), + ).toThrow("run Wait for PR again"); + expect(() => + validateGithubCiForMerge({ + state: "failure", + reason: "terminal-run", + detail: "Workflow failed.", + }), + ).toThrow("Workflow failed"); + }); }); diff --git a/scripts/lastcode-merge.ts b/scripts/lastcode-merge.ts index d51462fdd923f..e4721002aec85 100644 --- a/scripts/lastcode-merge.ts +++ b/scripts/lastcode-merge.ts @@ -6,14 +6,13 @@ import * as NodeChildProcess from "node:child_process"; import { assertBaseIsAncestor, assertCleanWorktree, - assertFullCiStamp, assertSupportedNodeVersion, LASTCODE_BASE_BRANCH, LASTCODE_ORIGIN_REMOTE, - resolveCommonGitDir, resolveRepoRoot, runGit, } from "./lastcode-local-ci.ts"; +import { type GithubCiEvidence, readGithubCi } from "./lastcode-github-ci.ts"; const LASTCODE_GITHUB_REPOSITORY = process.env.LASTCODE_GITHUB_REPOSITORY ?? "lastobelus/lastCode"; @@ -26,6 +25,7 @@ export interface PullRequestForMerge { readonly baseRefName: string; readonly baseRefOid: string; readonly mergeable: string; + readonly mergeStateStatus: string; } export function validatePullRequestForMerge( @@ -54,11 +54,32 @@ export function validatePullRequestForMerge( `Pull request #${pullRequest.number} is based on ${pullRequest.baseRefOid}, not the locally tested base ${expectedBase}.`, ); } - if (pullRequest.mergeable === "CONFLICTING") { - throw new Error(`Pull request #${pullRequest.number} has merge conflicts.`); + if (pullRequest.mergeable !== "MERGEABLE" || pullRequest.mergeStateStatus !== "CLEAN") { + throw new Error( + `Pull request #${pullRequest.number} is not cleanly mergeable (${pullRequest.mergeable}/${pullRequest.mergeStateStatus}).`, + ); } } +export function validateGithubCiForMerge(evidence: GithubCiEvidence): { + readonly runId: number; + readonly testedMergeSha: string; +} { + if (evidence.state === "satisfied" && evidence.reason === "exact-run") { + const { runId, testedMergeSha } = evidence; + if (runId === undefined || !testedMergeSha || !/^[0-9a-f]{40}$/u.test(testedMergeSha)) { + throw new Error("GitHub CI exact-run evidence is missing its immutable run identity."); + } + return { runId, testedMergeSha }; + } + if (evidence.state === "failure") { + throw new Error(`GitHub CI is not merge-ready: ${evidence.detail}`); + } + throw new Error( + `GitHub CI is not merge-ready (${evidence.state}/${evidence.reason}); run Wait for PR again.`, + ); +} + function runCommand( repoRoot: string, command: string, @@ -82,6 +103,22 @@ function runCommand( return capture ? result.stdout.trim() : ""; } +function runGhJson(repoRoot: string, args: ReadonlyArray): T { + return JSON.parse(runCommand(repoRoot, "gh", args, true)) as T; +} + +function readPullRequest(repoRoot: string, branch: string): PullRequestForMerge { + return runGhJson(repoRoot, [ + "pr", + "view", + branch, + "--repo", + LASTCODE_GITHUB_REPOSITORY, + "--json", + "number,url,state,isDraft,headRefOid,baseRefName,baseRefOid,mergeable,mergeStateStatus", + ]); +} + function main(argv: ReadonlyArray): void { assertSupportedNodeVersion(); const dryRun = argv.length === 1 && argv[0] === "--dry-run"; @@ -105,29 +142,37 @@ function main(argv: ReadonlyArray): void { `refs/remotes/${LASTCODE_ORIGIN_REMOTE}/${LASTCODE_BASE_BRANCH}`, ]); assertBaseIsAncestor(repoRoot, baseCommit, commit); - assertFullCiStamp(resolveCommonGitDir(repoRoot), commit, baseCommit); - - const pullRequest = JSON.parse( - runCommand( - repoRoot, - "gh", - [ - "pr", - "view", - branch, - "--repo", - LASTCODE_GITHUB_REPOSITORY, - "--json", - "number,url,state,isDraft,headRefOid,baseRefName,baseRefOid,mergeable", - ], - true, - ), - ) as PullRequestForMerge; + + const pullRequest = readPullRequest(repoRoot, branch); validatePullRequestForMerge(pullRequest, commit, baseCommit); + const githubCi = readGithubCi( + LASTCODE_GITHUB_REPOSITORY, + pullRequest, + (args: ReadonlyArray): T => runGhJson(repoRoot, args), + ); + const validatedGithubCi = validateGithubCiForMerge(githubCi); + + runCommand(repoRoot, "git", ["fetch", LASTCODE_ORIGIN_REMOTE, LASTCODE_BASE_BRANCH]); + const confirmedBaseCommit = runGit(repoRoot, [ + "rev-parse", + `refs/remotes/${LASTCODE_ORIGIN_REMOTE}/${LASTCODE_BASE_BRANCH}`, + ]); + if (confirmedBaseCommit !== baseCommit) { + throw new Error( + `${LASTCODE_ORIGIN_REMOTE}/${LASTCODE_BASE_BRANCH} moved from ${baseCommit} to ${confirmedBaseCommit} while validating GitHub CI.`, + ); + } + const confirmedPullRequest = readPullRequest(repoRoot, branch); + if (confirmedPullRequest.number !== pullRequest.number) { + throw new Error( + `Checked-out branch now resolves to pull request #${confirmedPullRequest.number}, not #${pullRequest.number}.`, + ); + } + validatePullRequestForMerge(confirmedPullRequest, commit, baseCommit); if (dryRun) { console.log( - `[lastcode:merge] Would squash ${pullRequest.url} at ${commit} into ${LASTCODE_BASE_BRANCH}.`, + `[lastcode:merge] Would squash ${pullRequest.url} at ${commit} into ${LASTCODE_BASE_BRANCH} after GitHub CI run ${validatedGithubCi.runId} tested merge ${validatedGithubCi.testedMergeSha}.`, ); return; } diff --git a/scripts/lastcode-wait-for-pr.ts b/scripts/lastcode-wait-for-pr.ts index 5c7084f602360..3f406f15eb704 100644 --- a/scripts/lastcode-wait-for-pr.ts +++ b/scripts/lastcode-wait-for-pr.ts @@ -3,18 +3,7 @@ // @effect-diagnostics nodeBuiltinImport:off globalConsole:off globalDate:off globalTimers:off -- Read-only host-side GitHub polling. import * as NodeChildProcess from "node:child_process"; -import { - evaluateGithubCi, - githubBranchRulesArgs, - githubCiJobsArgs, - githubCiRunsArgs, - githubCiWorkflowArgs, - type GithubBranchRule, - type GithubCiEvidence, - type GithubWorkflow, - type GithubWorkflowJob, - type GithubWorkflowRun, -} from "./lastcode-github-ci.ts"; +import { type GithubCiEvidence, readGithubCi } from "./lastcode-github-ci.ts"; const LASTCODE_GITHUB_REPOSITORY = process.env.LASTCODE_GITHUB_REPOSITORY ?? "lastobelus/lastCode"; const LASTCODE_BASE_BRANCH = "lastcode/main"; @@ -545,43 +534,6 @@ function runGhJson(args: ReadonlyArray): T { return JSON.parse(result.stdout) as T; } -type WorkflowRunsResponse = { - readonly workflow_runs?: ReadonlyArray; -}; - -type WorkflowJobsResponse = { - readonly jobs?: ReadonlyArray; -}; - -function readGithubCi(repository: string, pullRequest: PullRequestState): GithubCiEvidence { - const workflow = runGhJson(githubCiWorkflowArgs(repository)); - const branchRules = runGhJson>( - githubBranchRulesArgs(repository, pullRequest.baseRefName), - ); - const workflowRuns = - runGhJson(githubCiRunsArgs(repository, pullRequest.headRefOid)) - .workflow_runs ?? []; - const evaluation = { - workflow, - branchRules, - pullRequestNumber: pullRequest.number, - headSha: pullRequest.headRefOid, - baseSha: pullRequest.baseRefOid, - workflowRuns, - jobs: null, - } as const; - const provisional = evaluateGithubCi(evaluation); - const completedSuccessRun = workflowRuns.find( - (run) => - run.id === provisional.runId && run.status === "completed" && run.conclusion === "success", - ); - if (!completedSuccessRun?.id) return provisional; - const jobs = - runGhJson(githubCiJobsArgs(repository, completedSuccessRun.id)).jobs ?? - []; - return evaluateGithubCi({ ...evaluation, jobs }); -} - function paginatedGhApi(endpoint: string): ReadonlyArray { const pages = runGhJson>>([ "api", @@ -732,7 +684,7 @@ function readObservation(repository: string, branch: string): WaitObservation { const initialLocal = readLocalState(); const initialPullRequest = runGhJson(pullRequestViewArgs(repository, branch)); const initialReviewData = readReviewData(repository, initialPullRequest); - const ci = readGithubCi(repository, initialPullRequest); + const ci = readGithubCi(repository, initialPullRequest, runGhJson); const pullRequest = runGhJson(pullRequestViewArgs(repository, branch)); const local = readLocalState(); if ( @@ -746,7 +698,7 @@ function readObservation(repository: string, branch: string): WaitObservation { if (!requiresReadyConfirmation(observation)) return observation; const confirmedReviewData = readReviewData(repository, pullRequest); - const confirmedCi = readGithubCi(repository, pullRequest); + const confirmedCi = readGithubCi(repository, pullRequest, runGhJson); const confirmedPullRequest = runGhJson( pullRequestViewArgs(repository, branch), ); diff --git a/t3.json b/t3.json index 16f5673f61cd9..6d0ed0bf15a40 100644 --- a/t3.json +++ b/t3.json @@ -22,11 +22,6 @@ "name": "Build Intel package (macOS)", "command": "mise exec node@24.13.1 -- node scripts/lastcode-build-intel-package.ts run", "icon": "build" - }, - { - "name": "Run Full CI", - "command": "mise exec node@24.13.1 -- node scripts/lastcode-local-ci.ts --full", - "icon": "test" } ] }