From 200837f5bc045bb2f403f3f398e90fcdf73a2c67 Mon Sep 17 00:00:00 2001 From: "Marcus R. Brown" Date: Fri, 30 Oct 2026 20:14:22 -0700 Subject: [PATCH 1/2] fix(deps): regenerate the OpenCode V2 pin digests when Renovate bumps it (#1998) --- .agents/skills/versioned-tool/SKILL.md | 2 +- .github/renovate.json5 | 21 +++++--- STRUCTURE.md | 2 +- deploy/README.md | 8 +-- package.json | 1 + scripts/renovate-v2-pin-postupgrade.test.ts | 60 +++++++++++++++++++++ scripts/sync-opencode-v2-pin.test.ts | 2 +- scripts/sync-opencode-v2-pin.ts | 13 ++--- 8 files changed, 89 insertions(+), 20 deletions(-) create mode 100644 scripts/renovate-v2-pin-postupgrade.test.ts diff --git a/.agents/skills/versioned-tool/SKILL.md b/.agents/skills/versioned-tool/SKILL.md index b2cb32ce94..343179909a 100644 --- a/.agents/skills/versioned-tool/SKILL.md +++ b/.agents/skills/versioned-tool/SKILL.md @@ -20,7 +20,7 @@ This project manages external CLI tools through a **single-source-of-truth versi | Systematic | `DEFAULT_SYSTEMATIC_VERSION` | `systematic-version` | `npm` (`@fro.bot/systematic`) | | OpenCode (harness base) | `base_version` in `packages/harness/harness.config.json` | _(internal only — config-JSON, not a TS constant)_ | `github-releases` (`anomalyco/opencode`) | -**Release-job coupled sites (not Renovate-tracked):** `DEFAULT_OPENCODE_VERSION` and the workspace `ARG OPENCODE_VERSION` hold the harness build version (`+harness.`); the Dockerfile ARG default stays this V1 harness build, and V2 is selected by build-arg instead. Renovate cannot order SemVer build-metadata tags, so both are bumped together by `harness-release.yaml`'s `sync-default-version` job at publish time (one auto-PR, dual-source idempotency guard). Do not add Renovate `customManager` entries for these — they would be dropped. **V2 pin:** the JSON file's `version` is Renovate-tracked, but its per-asset digests are not; after a bump, run `node scripts/sync-opencode-v2-pin.ts` and commit the result (see `deploy/README.md` § OpenCode V2). See `docs/solutions/best-practices/cross-libc-build-and-release-safety-2026-06-14.md` §4 and `docs/solutions/workflow-issues/harness-base-version-source-of-truth-2026-06-12.md`. +**Release-job coupled sites (not Renovate-tracked):** `DEFAULT_OPENCODE_VERSION` and the workspace `ARG OPENCODE_VERSION` hold the harness build version (`+harness.`); the Dockerfile ARG default stays this V1 harness build, and V2 is selected by build-arg instead. Renovate cannot order SemVer build-metadata tags, so both are bumped together by `harness-release.yaml`'s `sync-default-version` job at publish time (one auto-PR, dual-source idempotency guard). Do not add Renovate `customManager` entries for these — they would be dropped. **V2 pin:** Renovate bumps the JSON file's `version`; its per-asset digests are not Renovate-tracked, so the rule's `postUpgradeTasks` run `bun run postupgrade` (`scripts/sync-opencode-v2-pin.ts`) to regenerate them on the update branch. Any command added there must match the runner's `allowedCommands` (see `scripts/renovate-v2-pin-postupgrade.test.ts`; `node scripts/...` is not allowed). See `deploy/README.md` § OpenCode V2. See `docs/solutions/best-practices/cross-libc-build-and-release-safety-2026-06-14.md` §4 and `docs/solutions/workflow-issues/harness-base-version-source-of-truth-2026-06-12.md`. ## Quick Start diff --git a/.github/renovate.json5 b/.github/renovate.json5 index daa1447a74..4521faee2e 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -85,8 +85,8 @@ { // Tracks the stock OpenCode V2 pin. The Dockerfile's `opencode-v2` stage and the Action's // installOpenCode both read this file. Bumping `version` alone leaves the per-asset sha256 - // digests stale, and both consumers fail closed on that: the digests are regenerated by - // `scripts/sync-opencode-v2-pin.ts` (see the packageRules entry below). + // digests stale, and both consumers fail closed on that: the packageRules entry below regenerates + // the digests on the update branch with `bun run postupgrade` (scripts/sync-opencode-v2-pin.ts). customType: 'regex', managerFilePatterns: ['/packages\\/runtime\\/src\\/shared\\/opencode-v2-pin\\.json/'], matchStrings: ['"version":\\s*"(?\\d+\\.\\d+\\.\\d+)"'], @@ -164,16 +164,23 @@ // The V2 pin lives in its own file and follows its own major, so the V1 cap above does not // apply to it. This entry must stay AFTER that cap (a later rule wins) and must not become the // first `anomalyco/opencode` rule with `allowedVersions`: pin-invariants.test.ts reads the cap - // from the first one. The pin PR cannot pass CI as Renovate opens it, because the per-asset - // digests still describe the old version; prBodyNotes tells the reviewer how to fix that. + // from the first one. + // + // Renovate only changes `version`; the per-asset sha256 digests still describe the old release, and the + // Dockerfile and the Action both fail closed on that. `bun run postupgrade` (scripts/sync-opencode-v2-pin.ts) + // rewrites the digests from the release's SHA256SUMS on the update branch. A rule-level `postUpgradeTasks` + // REPLACES the top-level one rather than merging with it, so the full list is repeated here on purpose, with + // the sync between install and build. Every command must match the self-hosted runner's `allowedCommands` + // (pinned by scripts/renovate-v2-pin-postupgrade.test.ts); `node scripts/...` is not allowed there. matchFileNames: ['packages/runtime/src/shared/opencode-v2-pin.json'], matchPackageNames: ['anomalyco/opencode'], allowedVersions: '/^2\\./', commitMessageTopic: 'OpenCode V2 pin', automerge: false, - prBodyNotes: [ - 'This only bumps `version`. Regenerate the sha256 digests before merging: `node scripts/sync-opencode-v2-pin.ts`, then commit `packages/runtime/src/shared/opencode-v2-pin.json`. CI builds the V2 workspace image against the new pin.', - ], + postUpgradeTasks: { + commands: ['bun install --ignore-scripts', 'bun run postupgrade', 'bun run build'], + executionMode: 'branch', + }, }, { // Cap Bun at 1.4.4. The build gate requires an exact match with upstream diff --git a/STRUCTURE.md b/STRUCTURE.md index 04f0984d47..c7b7bff862 100644 --- a/STRUCTURE.md +++ b/STRUCTURE.md @@ -101,7 +101,7 @@ fro-bot/agent/ - **`deploy/plugins/`**, **`deploy/managed-config/`** — the baked OpenCode reuse-guard plugin (`no-task-reuse.mjs`) and the root-owned managed config (`/etc/opencode/opencode.json`) that loads it; plain Node ESM / JSON, tested from `deploy/scripts/*.test.mjs`. The same `no-task-reuse.mjs` is the single source for the Action's guard: `tsdown.config.ts` builds it into `dist/no-task-reuse.js`, and `src/services/setup/no-task-reuse-config.ts` copies it into the CI OpenCode config dir at every Action server start (`no-task-reuse.d.mts` types it for the Vitest suite). - **`deploy/scripts/`** — Plain Node ESM (`.mjs`) helpers for deploy-time operations (auth validation, config merge, protected-dir creation, legacy checkout ownership migration, agent-side config provisioning, V2 plugin install and image smoke); uses `node --test`, not Vitest. - **`deploy/tests/`** — `isolation-harness.sh`, the CI acceptance harness that proves the service/agent uid boundary in a real container started with production's security posture. -- **`scripts/`** — Repo-level build tooling: action dist builder, hidden-Unicode scrubber, third-party notices, release dispatch, and `sync-opencode-v2-pin.ts` (regenerates the OpenCode V2 pin's digests on a Renovate bump). +- **`scripts/`** — Repo-level build tooling: action dist builder, hidden-Unicode scrubber, third-party notices, release dispatch, and `sync-opencode-v2-pin.ts` (regenerates the OpenCode V2 pin's digests; Renovate runs it as `bun run postupgrade`). - **`evals/`** — Gated agent-outcome eval corpus that runs the real execution path against disposable fixture repos; the pure gate and baseline tests run in normal CI, while live scenarios require `FRO_BOT_EVAL=1`. - **`.github/workflows/`** — All CI/CD automation; 12 workflow files covering tests, releases, security scanning, and bot triggers. - **`RFCs/`** — 19 architecture specification documents; read before making cross-cutting changes. diff --git a/deploy/README.md b/deploy/README.md index 67a3327186..e7c436489d 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -570,14 +570,14 @@ A major of 2 or higher selects the V2 path; the value must equal the pin's `vers **Paired deploy.** Deploy a gateway that includes the V2 run loop (#1985) before the V2 workspace, or together with it, from the same ref. A gateway without that loop runs the V1 loop against a V2 server, which is unsafe. A V2-capable gateway in front of a V1 workspace is safe. The shared control-API token requirement above applies to both. -**Bumping the pin.** Renovate opens a PR that changes only `version` (major 2 only; no automerge). Regenerate the digests before merging: +**Bumping the pin.** Renovate opens the PR (major 2 only; no automerge). It changes `version`, then its post-upgrade tasks run `bun run postupgrade` (`scripts/sync-opencode-v2-pin.ts`), which rewrites every asset digest from the release's `SHA256SUMS`, before the build. The PR already carries matching digests. To run the same step by hand: ```bash -node scripts/sync-opencode-v2-pin.ts # rewrite the digests from the release's SHA256SUMS -node scripts/sync-opencode-v2-pin.ts --check # exit 1 if the file disagrees with upstream +bun scripts/sync-opencode-v2-pin.ts # rewrite the digests from the release's SHA256SUMS +bun scripts/sync-opencode-v2-pin.ts --check # exit 1 if the file disagrees with upstream ``` -Commit the updated `opencode-v2-pin.json`. The **Workspace Image Smoke Test** CI job builds the image against the pin, starts it with no network, and fails on a stale digest. +The **Workspace Image Smoke Test** CI job builds the image against the pin, starts it with no network, and fails on a stale digest. **Revert.** Before switching, record the digests of the running workspace and gateway images. To revert, redeploy those previous workspace and gateway images by digest. Rebuilding an older ref does not reproduce the same digests. diff --git a/package.json b/package.json index a545ebc440..2265b7ea33 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "dist:escape-hidden-unicode": "node --experimental-strip-types scripts/escape-dist-hidden-unicode.ts", "fix": "bun run --filter @fro-bot/runtime fix && bun run --filter @fro-bot/action fix && bun run --filter @fro.bot/harness fix && bun run --filter @fro.bot/opencode-plugin fix && bun run --filter @fro-bot/gateway fix && bun run --filter @fro-bot/workspace-agent fix", "postinstall": "simple-git-hooks", + "postupgrade": "bun scripts/sync-opencode-v2-pin.ts", "lint": "bun run --filter @fro-bot/runtime lint && bun run --filter @fro-bot/action lint && bun run --filter @fro.bot/harness lint && bun run --filter @fro.bot/opencode-plugin lint && bun run --filter @fro-bot/gateway lint && bun run --filter @fro-bot/workspace-agent lint && bun run dist:check-hidden-unicode && bun run check:md-links", "test": "bun run --filter @fro-bot/runtime test && bun run --filter @fro-bot/action test && bun run --filter @fro-bot/workspace-agent test && bun run --filter @fro.bot/harness test && bun run --filter @fro.bot/opencode-plugin test && bun run --filter @fro-bot/gateway test && bun run test:evals", "evals:baseline:update": "bun run evals/update-baseline.ts", diff --git a/scripts/renovate-v2-pin-postupgrade.test.ts b/scripts/renovate-v2-pin-postupgrade.test.ts new file mode 100644 index 0000000000..f194ce960c --- /dev/null +++ b/scripts/renovate-v2-pin-postupgrade.test.ts @@ -0,0 +1,60 @@ +import {readFileSync} from 'node:fs' + +import {describe, expect, it} from 'vitest' + +// Source of truth: `allowedCommands` in bfra-me/renovate-action `action.yaml` (the `zzglobal_config` block), which the +// self-hosted runner applies and this repo cannot override. Only the patterns the V2-pin rule relies on are copied; if +// the action changes them, update these two and the rule's commands together. A command outside this list is silently +// refused on the runner, which leaves the pin PR with stale digests. +const ALLOWED_COMMANDS: readonly RegExp[] = [ + /^(bun|pnpm|yarn) install( --force)?( --frozen-lockfile)?( --ignore-scripts)?$/, + /^(?:bun|npm|pnpm|yarn)(?:\srun)?\s(?:bootstrap|build(-release)?|check|clean|fix|format|generate|lint|postupgrade|typecheck|update-snapshots)$/, +] + +const renovateText = readFileSync(new URL('../.github/renovate.json5', import.meta.url), 'utf8') +const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')) as { + readonly scripts: Readonly> +} + +// `.github/renovate.json5` is JSON5 and the repo has no JSON5 parser (see packages/harness/src/pin-invariants.test.ts), so +// the rule is cut out as text: from its `matchFileNames` line to the rule's closing brace at packageRules indent. +const ruleMatch = /matchFileNames: \['packages\/runtime\/src\/shared\/opencode-v2-pin\.json'\][\s\S]*?\n {4}\},/.exec( + renovateText, +) +const rule = ruleMatch?.[0] ?? '' + +function ruleCommands(): readonly string[] { + const list = /postUpgradeTasks:\s*\{[\s\S]*?commands:\s*\[([^\]]*)\]/.exec(rule)?.[1] ?? '' + return [...list.matchAll(/'([^']+)'/g)].map(match => match[1] ?? '') +} + +describe('OpenCode V2 pin Renovate rule', () => { + it('runs install, the digest sync, then build, in that order', () => { + // #given the rule that matches the pin file + expect(rule).not.toBe('') + + // #when reading its post-upgrade commands / #then the sync sits between install and build, branch mode + expect(ruleCommands()).toEqual(['bun install --ignore-scripts', 'bun run postupgrade', 'bun run build']) + expect(rule).toMatch(/executionMode: 'branch'/) + }) + + it('uses only commands the self-hosted runner allows', () => { + // #given the commands / #when each is checked against the runner's allowedCommands + const refused = ruleCommands().filter(command => !ALLOWED_COMMANDS.some(pattern => pattern.test(command))) + + // #then none is refused (`node scripts/...` would be) + expect(refused).toEqual([]) + expect(ALLOWED_COMMANDS.some(pattern => pattern.test('node scripts/sync-opencode-v2-pin.ts'))).toBe(false) + }) + + it('no longer asks a human to run the sync', () => { + // #given / #when / #then + expect(rule).not.toContain('prBodyNotes') + }) + + it('has a postupgrade script that runs the sync under bun, and the build script it chains to', () => { + // #given the root scripts / #when / #then + expect(packageJson.scripts.postupgrade).toBe('bun scripts/sync-opencode-v2-pin.ts') + expect(packageJson.scripts.build).toBeDefined() + }) +}) diff --git a/scripts/sync-opencode-v2-pin.test.ts b/scripts/sync-opencode-v2-pin.test.ts index 08a8e1a44b..7975321b08 100644 --- a/scripts/sync-opencode-v2-pin.test.ts +++ b/scripts/sync-opencode-v2-pin.test.ts @@ -163,7 +163,7 @@ describe('main', () => { // #then it exits 2 with a usage line and touched nothing expect(code).toBe(EXIT_USAGE) - expect(h.err.join('')).toContain('usage: node scripts/sync-opencode-v2-pin.ts') + expect(h.err.join('')).toContain('usage: bun scripts/sync-opencode-v2-pin.ts') expect(h.fetchMock).not.toHaveBeenCalled() expect(h.writes).toEqual([]) }, diff --git a/scripts/sync-opencode-v2-pin.ts b/scripts/sync-opencode-v2-pin.ts index 45e9040819..96929aaf70 100644 --- a/scripts/sync-opencode-v2-pin.ts +++ b/scripts/sync-opencode-v2-pin.ts @@ -1,11 +1,12 @@ #!/usr/bin/env node // Regenerates the per-asset sha256 digests in packages/runtime/src/shared/opencode-v2-pin.json from the upstream -// release's SHA256SUMS. Run it on the Renovate bump PR, which changes only `version`: +// release's SHA256SUMS. Renovate changes only `version`, then runs this as `bun run postupgrade` on the update branch +// (.github/renovate.json5, the OpenCode V2 pin rule). It also runs by hand: // -// node scripts/sync-opencode-v2-pin.ts # rewrite the digests for the pinned version -// node scripts/sync-opencode-v2-pin.ts 2.3.0 # set the version too, then rewrite the digests -// node scripts/sync-opencode-v2-pin.ts --check # exit 1 if the file disagrees with upstream; writes nothing +// bun scripts/sync-opencode-v2-pin.ts # rewrite the digests for the pinned version +// bun scripts/sync-opencode-v2-pin.ts 2.3.0 # set the version too, then rewrite the digests +// bun scripts/sync-opencode-v2-pin.ts --check # exit 1 if the file disagrees with upstream; writes nothing // // The only option is `--check`, and at most one positional version is accepted. Anything else (`--help`, `--check=true`, // a second positional) exits 2 with a usage line, before the pin is read, fetched or written. @@ -14,7 +15,7 @@ // release has no SHA256SUMS line for one. The Dockerfile's `opencode-v2` stage and the Action's installOpenCode // re-verify each digest against SHA256SUMS and the archive at install time, so a wrong digest cannot ship silently. // -// Plain Node (24 strips types), no dependencies. The relative `.ts` extensions in sibling scripts follow the same rule. +// No dependencies, and no runtime-specific API: it runs under bun (the Renovate runner) and under Node 24, which strips types. import {readFileSync, writeFileSync} from 'node:fs' import process from 'node:process' @@ -82,7 +83,7 @@ function serializePin(pin: OpenCodeV2Pin): string { return `${JSON.stringify(pin, null, 2)}\n` } -const USAGE = 'usage: node scripts/sync-opencode-v2-pin.ts [--check | ]' +const USAGE = 'usage: bun scripts/sync-opencode-v2-pin.ts [--check | ]' /** The exit code for a rejected command line (distinct from 1, a failed sync or check). */ export const EXIT_USAGE = 2 From 02abbb7bfcbdfb3eda7b144db960a4bb62b01cbc Mon Sep 17 00:00:00 2001 From: "fro-bot[bot]" <109017866+fro-bot[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 20:41:02 -0700 Subject: [PATCH 2/2] build(deps): update Systematic to v3.28.0 (#1997) Co-authored-by: fro-bot[bot] <109017866+fro-bot[bot]@users.noreply.github.com> --- deploy/workspace.Dockerfile | 2 +- dist/{artifact-BIg7elxR.js => artifact-C0wQlV2Q.js} | 2 +- dist/main.js | 2 +- dist/post.js | 2 +- packages/runtime/src/shared/constants.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename dist/{artifact-BIg7elxR.js => artifact-C0wQlV2Q.js} (99%) diff --git a/deploy/workspace.Dockerfile b/deploy/workspace.Dockerfile index c55bd56d4b..c17d962ccc 100644 --- a/deploy/workspace.Dockerfile +++ b/deploy/workspace.Dockerfile @@ -233,7 +233,7 @@ WORKDIR /app # in the form +harness.. Bumped in lockstep with the action default # by the harness-release workflow; merge the auto-PR to advance both surfaces. ARG OPENCODE_VERSION=1.19.4+harness.5bde2635 -ARG SYSTEMATIC_VERSION=3.27.2 +ARG SYSTEMATIC_VERSION=3.28.0 # System packages come from the base image's Alpine 3.24 branch and are not # pinned: the branch index drops older versions, so exact pins would break the diff --git a/dist/artifact-BIg7elxR.js b/dist/artifact-C0wQlV2Q.js similarity index 99% rename from dist/artifact-BIg7elxR.js rename to dist/artifact-C0wQlV2Q.js index 4c5925968f..dc4e8c9376 100644 --- a/dist/artifact-BIg7elxR.js +++ b/dist/artifact-C0wQlV2Q.js @@ -325,7 +325,7 @@ ${c}`}function Gh(e,t,n){let r=[t];if(e.recentSessions.length>0){r.push(``),r.pu `);o=c.pop()??``;for(let e of c){let i=e.split(` `),a=[],o;for(let e of i)if(e.startsWith(`data:`))a.push(e.replace(/^data:\s*/,``));else if(e.startsWith(`event:`))o=e.replace(/^event:\s*/,``);else if(e.startsWith(`id:`))u=e.replace(/^id:\s*/,``);else if(e.startsWith(`retry:`)){let t=Number.parseInt(e.replace(/^retry:\s*/,``),10);Number.isNaN(t)||(s=t)}let c,l=!1;if(a.length){let e=a.join(` `);try{c=JSON.parse(e),l=!0}catch{c=e}}l&&(r&&await r(c),n&&(c=await n(c))),t?.({data:c,event:o,id:u,retry:s}),a.length&&(yield c)}}}finally{p.removeEventListener(`abort`,d),a.releaseLock()}break}catch(t){if(e?.(t),a!==void 0&&f>=a)break;let n=Math.min(s*2**(f-1),o??3e4);await d(n)}}}()}},Kh=async(e,t)=>{let n=typeof t==`function`?await t(e):t;if(n)return e.scheme===`bearer`?`Bearer ${n}`:e.scheme===`basic`?`Basic ${btoa(n)}`:n},Pee={bodySerializer:e=>JSON.stringify(e,(e,t)=>typeof t==`bigint`?t.toString():t)},Fee=e=>{switch(e){case`label`:return`.`;case`matrix`:return`;`;case`simple`:return`,`;default:return`&`}},Iee=e=>{switch(e){case`form`:return`,`;case`pipeDelimited`:return`|`;case`spaceDelimited`:return`%20`;default:return`,`}},Lee=e=>{switch(e){case`label`:return`.`;case`matrix`:return`;`;case`simple`:return`,`;default:return`&`}},qh=({allowReserved:e,explode:t,name:n,style:r,value:i})=>{if(!t){let t=(e?i:i.map(e=>encodeURIComponent(e))).join(Iee(r));switch(r){case`label`:return`.${t}`;case`matrix`:return`;${n}=${t}`;case`simple`:return t;default:return`${n}=${t}`}}let a=Fee(r),o=i.map(t=>r===`label`||r===`simple`?e?t:encodeURIComponent(t):Jh({allowReserved:e,name:n,value:t})).join(a);return r===`label`||r===`matrix`?a+o:o},Jh=({allowReserved:e,name:t,value:n})=>{if(n==null)return``;if(typeof n==`object`)throw Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");return`${t}=${e?n:encodeURIComponent(n)}`},Yh=({allowReserved:e,explode:t,name:n,style:r,value:i,valueOnly:a})=>{if(i instanceof Date)return a?i.toISOString():`${n}=${i.toISOString()}`;if(r!==`deepObject`&&!t){let t=[];Object.entries(i).forEach(([n,r])=>{t=[...t,n,e?r:encodeURIComponent(r)]});let a=t.join(`,`);switch(r){case`form`:return`${n}=${a}`;case`label`:return`.${a}`;case`matrix`:return`;${n}=${a}`;default:return a}}let o=Lee(r),s=Object.entries(i).map(([t,i])=>Jh({allowReserved:e,name:r===`deepObject`?`${n}[${t}]`:t,value:i})).join(o);return r===`label`||r===`matrix`?o+s:s},Ree=/\{[^{}]+\}/g,zee=({path:e,url:t})=>{let n=t,r=t.match(Ree);if(r)for(let t of r){let r=!1,i=t.substring(1,t.length-1),a=`simple`;i.endsWith(`*`)&&(r=!0,i=i.substring(0,i.length-1)),i.startsWith(`.`)?(i=i.substring(1),a=`label`):i.startsWith(`;`)&&(i=i.substring(1),a=`matrix`);let o=e[i];if(o==null)continue;if(Array.isArray(o)){n=n.replace(t,qh({explode:r,name:i,style:a,value:o}));continue}if(typeof o==`object`){n=n.replace(t,Yh({explode:r,name:i,style:a,value:o,valueOnly:!0}));continue}if(a===`matrix`){n=n.replace(t,`;${Jh({name:i,value:o})}`);continue}let s=encodeURIComponent(a===`label`?`.${o}`:o);n=n.replace(t,s)}return n},Bee=({baseUrl:e,path:t,query:n,querySerializer:r,url:i})=>{let a=i.startsWith(`/`)?i:`/${i}`,o=(e??``)+a;t&&(o=zee({path:t,url:o}));let s=n?r(n):``;return s.startsWith(`?`)&&(s=s.substring(1)),s&&(o+=`?${s}`),o},Xh=({allowReserved:e,array:t,object:n}={})=>r=>{let i=[];if(r&&typeof r==`object`)for(let a in r){let o=r[a];if(o!=null){if(Array.isArray(o)){let n=qh({allowReserved:e,explode:!0,name:a,style:`form`,value:o,...t});n&&i.push(n)}else if(typeof o==`object`){let t=Yh({allowReserved:e,explode:!0,name:a,style:`deepObject`,value:o,...n});t&&i.push(t)}else{let t=Jh({allowReserved:e,name:a,value:o});t&&i.push(t)}}}return i.join(`&`)},Vee=e=>{if(!e)return`stream`;let t=e.split(`;`)[0]?.trim();if(t){if(t.startsWith(`application/json`)||t.endsWith(`+json`))return`json`;if(t===`multipart/form-data`)return`formData`;if([`application/`,`audio/`,`image/`,`video/`].some(e=>t.startsWith(e)))return`blob`;if(t.startsWith(`text/`))return`text`}},Hee=(e,t)=>t?!!(e.headers.has(t)||e.query?.[t]||e.headers.get(`Cookie`)?.includes(`${t}=`)):!1,Uee=async({security:e,...t})=>{for(let n of e){if(Hee(t,n.name))continue;let e=await Kh(n,t.auth);if(!e)continue;let r=n.name??`Authorization`;switch(n.in){case`query`:t.query||={},t.query[r]=e;break;case`cookie`:t.headers.append(`Cookie`,`${r}=${e}`);break;default:t.headers.set(r,e)}}},Zh=e=>Bee({baseUrl:e.baseUrl,path:e.path,query:e.query,querySerializer:typeof e.querySerializer==`function`?e.querySerializer:Xh(e.querySerializer),url:e.url}),Qh=(e,t)=>{let n={...e,...t};return n.baseUrl?.endsWith(`/`)&&(n.baseUrl=n.baseUrl.substring(0,n.baseUrl.length-1)),n.headers=$h(e.headers,t.headers),n},$h=(...e)=>{let t=new Headers;for(let n of e){if(!n||typeof n!=`object`)continue;let e=n instanceof Headers?n.entries():Object.entries(n);for(let[n,r]of e)if(r===null)t.delete(n);else if(Array.isArray(r))for(let e of r)t.append(n,e);else r!==void 0&&t.set(n,typeof r==`object`?JSON.stringify(r):r)}return t};var eg=class{_fns;constructor(){this._fns=[]}clear(){this._fns=[]}getInterceptorIndex(e){return typeof e==`number`?this._fns[e]?e:-1:this._fns.indexOf(e)}exists(e){let t=this.getInterceptorIndex(e);return!!this._fns[t]}eject(e){let t=this.getInterceptorIndex(e);this._fns[t]&&(this._fns[t]=null)}update(e,t){let n=this.getInterceptorIndex(e);return this._fns[n]?(this._fns[n]=t,e):!1}use(e){return this._fns=[...this._fns,e],this._fns.length-1}};const Wee=()=>({error:new eg,request:new eg,response:new eg}),Gee=Xh({allowReserved:!1,array:{explode:!0,style:`form`},object:{explode:!0,style:`deepObject`}}),tg={"Content-Type":`application/json`},ng=(e={})=>({...Pee,headers:tg,parseAs:`auto`,querySerializer:Gee,...e}),rg=(e={})=>{let t=Qh(ng(),e),n=()=>({...t}),r=e=>(t=Qh(t,e),n()),i=Wee(),a=async e=>{let n={...t,...e,fetch:e.fetch??t.fetch??globalThis.fetch,headers:$h(t.headers,e.headers),serializedBody:void 0};return n.security&&await Uee({...n,security:n.security}),n.requestValidator&&await n.requestValidator(n),n.body&&n.bodySerializer&&(n.serializedBody=n.bodySerializer(n.body)),(n.serializedBody===void 0||n.serializedBody===``)&&n.headers.delete(`Content-Type`),{opts:n,url:Zh(n)}},o=async e=>{let{opts:t,url:n}=await a(e),r={redirect:`follow`,...t,body:t.serializedBody},o=new Request(n,r);for(let e of i.request._fns)e&&(o=await e(o,t));let s=t.fetch,c=await s(o);for(let e of i.response._fns)e&&(c=await e(c,o,t));let l={request:o,response:c};if(c.ok){if(c.status===204||c.headers.get(`Content-Length`)===`0`)return t.responseStyle===`data`?{}:{data:{},...l};let e=(t.parseAs===`auto`?Vee(c.headers.get(`Content-Type`)):t.parseAs)??`json`,n;switch(e){case`arrayBuffer`:case`blob`:case`formData`:case`json`:case`text`:n=await c[e]();break;case`stream`:return t.responseStyle===`data`?c.body:{data:c.body,...l}}return e===`json`&&(t.responseValidator&&await t.responseValidator(n),t.responseTransformer&&(n=await t.responseTransformer(n))),t.responseStyle===`data`?n:{data:n,...l}}let u=await c.text(),d;try{d=JSON.parse(u)}catch{}let f=d??u,p=f;for(let e of i.error._fns)e&&(p=await e(f,c,o,t));if(p||={},t.throwOnError)throw p;return t.responseStyle===`data`?void 0:{error:p,...l}},s=e=>{let t=t=>o({...t,method:e});return t.sse=async t=>{let{opts:n,url:r}=await a(t);return Nee({...n,body:n.body,headers:n.headers,method:e,url:r})},t};return{buildUrl:Zh,connect:s(`CONNECT`),delete:s(`DELETE`),get:s(`GET`),getConfig:n,head:s(`HEAD`),interceptors:i,options:s(`OPTIONS`),patch:s(`PATCH`),post:s(`POST`),put:s(`PUT`),request:o,setConfig:r,trace:s(`TRACE`)}};Object.entries({$body_:`body`,$headers_:`headers`,$path_:`path`,$query_:`query`});const ig=rg(ng({baseUrl:`http://localhost:4096`}));var ag=class{_client=ig;constructor(e){e?.client&&(this._client=e.client)}},og=class extends ag{event(e){return(e?.client??this._client).get.sse({url:`/global/event`,...e})}},sg=class extends ag{list(e){return(e?.client??this._client).get({url:`/project`,...e})}current(e){return(e?.client??this._client).get({url:`/project/current`,...e})}},cg=class extends ag{list(e){return(e?.client??this._client).get({url:`/pty`,...e})}create(e){return(e?.client??this._client).post({url:`/pty`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}remove(e){return(e.client??this._client).delete({url:`/pty/{id}`,...e})}get(e){return(e.client??this._client).get({url:`/pty/{id}`,...e})}update(e){return(e.client??this._client).put({url:`/pty/{id}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}connect(e){return(e.client??this._client).get({url:`/pty/{id}/connect`,...e})}},lg=class extends ag{get(e){return(e?.client??this._client).get({url:`/config`,...e})}update(e){return(e?.client??this._client).patch({url:`/config`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}providers(e){return(e?.client??this._client).get({url:`/config/providers`,...e})}},ug=class extends ag{ids(e){return(e?.client??this._client).get({url:`/experimental/tool/ids`,...e})}list(e){return(e.client??this._client).get({url:`/experimental/tool`,...e})}},dg=class extends ag{dispose(e){return(e?.client??this._client).post({url:`/instance/dispose`,...e})}},fg=class extends ag{get(e){return(e?.client??this._client).get({url:`/path`,...e})}},pg=class extends ag{get(e){return(e?.client??this._client).get({url:`/vcs`,...e})}},mg=class extends ag{list(e){return(e?.client??this._client).get({url:`/session`,...e})}create(e){return(e?.client??this._client).post({url:`/session`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}status(e){return(e?.client??this._client).get({url:`/session/status`,...e})}delete(e){return(e.client??this._client).delete({url:`/session/{id}`,...e})}get(e){return(e.client??this._client).get({url:`/session/{id}`,...e})}update(e){return(e.client??this._client).patch({url:`/session/{id}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}children(e){return(e.client??this._client).get({url:`/session/{id}/children`,...e})}todo(e){return(e.client??this._client).get({url:`/session/{id}/todo`,...e})}init(e){return(e.client??this._client).post({url:`/session/{id}/init`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}fork(e){return(e.client??this._client).post({url:`/session/{id}/fork`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}abort(e){return(e.client??this._client).post({url:`/session/{id}/abort`,...e})}unshare(e){return(e.client??this._client).delete({url:`/session/{id}/share`,...e})}share(e){return(e.client??this._client).post({url:`/session/{id}/share`,...e})}diff(e){return(e.client??this._client).get({url:`/session/{id}/diff`,...e})}summarize(e){return(e.client??this._client).post({url:`/session/{id}/summarize`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}messages(e){return(e.client??this._client).get({url:`/session/{id}/message`,...e})}prompt(e){return(e.client??this._client).post({url:`/session/{id}/message`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}message(e){return(e.client??this._client).get({url:`/session/{id}/message/{messageID}`,...e})}promptAsync(e){return(e.client??this._client).post({url:`/session/{id}/prompt_async`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}command(e){return(e.client??this._client).post({url:`/session/{id}/command`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}shell(e){return(e.client??this._client).post({url:`/session/{id}/shell`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}revert(e){return(e.client??this._client).post({url:`/session/{id}/revert`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}unrevert(e){return(e.client??this._client).post({url:`/session/{id}/unrevert`,...e})}},hg=class extends ag{list(e){return(e?.client??this._client).get({url:`/command`,...e})}},gg=class extends ag{authorize(e){return(e.client??this._client).post({url:`/provider/{id}/oauth/authorize`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}callback(e){return(e.client??this._client).post({url:`/provider/{id}/oauth/callback`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}},_g=class extends ag{list(e){return(e?.client??this._client).get({url:`/provider`,...e})}auth(e){return(e?.client??this._client).get({url:`/provider/auth`,...e})}oauth=new gg({client:this._client})},vg=class extends ag{text(e){return(e.client??this._client).get({url:`/find`,...e})}files(e){return(e.client??this._client).get({url:`/find/file`,...e})}symbols(e){return(e.client??this._client).get({url:`/find/symbol`,...e})}},yg=class extends ag{list(e){return(e.client??this._client).get({url:`/file`,...e})}read(e){return(e.client??this._client).get({url:`/file/content`,...e})}status(e){return(e?.client??this._client).get({url:`/file/status`,...e})}},bg=class extends ag{log(e){return(e?.client??this._client).post({url:`/log`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}agents(e){return(e?.client??this._client).get({url:`/agent`,...e})}},xg=class extends ag{remove(e){return(e.client??this._client).delete({url:`/mcp/{name}/auth`,...e})}start(e){return(e.client??this._client).post({url:`/mcp/{name}/auth`,...e})}callback(e){return(e.client??this._client).post({url:`/mcp/{name}/auth/callback`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}authenticate(e){return(e.client??this._client).post({url:`/mcp/{name}/auth/authenticate`,...e})}set(e){return(e.client??this._client).put({url:`/auth/{id}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}},Sg=class extends ag{status(e){return(e?.client??this._client).get({url:`/mcp`,...e})}add(e){return(e?.client??this._client).post({url:`/mcp`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}connect(e){return(e.client??this._client).post({url:`/mcp/{name}/connect`,...e})}disconnect(e){return(e.client??this._client).post({url:`/mcp/{name}/disconnect`,...e})}auth=new xg({client:this._client})},Cg=class extends ag{status(e){return(e?.client??this._client).get({url:`/lsp`,...e})}},wg=class extends ag{status(e){return(e?.client??this._client).get({url:`/formatter`,...e})}},Tg=class extends ag{next(e){return(e?.client??this._client).get({url:`/tui/control/next`,...e})}response(e){return(e?.client??this._client).post({url:`/tui/control/response`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}},Eg=class extends ag{appendPrompt(e){return(e?.client??this._client).post({url:`/tui/append-prompt`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}openHelp(e){return(e?.client??this._client).post({url:`/tui/open-help`,...e})}openSessions(e){return(e?.client??this._client).post({url:`/tui/open-sessions`,...e})}openThemes(e){return(e?.client??this._client).post({url:`/tui/open-themes`,...e})}openModels(e){return(e?.client??this._client).post({url:`/tui/open-models`,...e})}submitPrompt(e){return(e?.client??this._client).post({url:`/tui/submit-prompt`,...e})}clearPrompt(e){return(e?.client??this._client).post({url:`/tui/clear-prompt`,...e})}executeCommand(e){return(e?.client??this._client).post({url:`/tui/execute-command`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}showToast(e){return(e?.client??this._client).post({url:`/tui/show-toast`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}publish(e){return(e?.client??this._client).post({url:`/tui/publish`,...e,headers:{"Content-Type":`application/json`,...e?.headers}})}control=new Tg({client:this._client})},Dg=class extends ag{subscribe(e){return(e?.client??this._client).get.sse({url:`/event`,...e})}},Og=class extends ag{postSessionIdPermissionsPermissionId(e){return(e.client??this._client).post({url:`/session/{id}/permissions/{permissionID}`,...e,headers:{"Content-Type":`application/json`,...e.headers}})}global=new og({client:this._client});project=new sg({client:this._client});pty=new cg({client:this._client});config=new lg({client:this._client});tool=new ug({client:this._client});instance=new dg({client:this._client});path=new fg({client:this._client});vcs=new pg({client:this._client});session=new mg({client:this._client});command=new hg({client:this._client});provider=new _g({client:this._client});find=new vg({client:this._client});file=new yg({client:this._client});app=new bg({client:this._client});mcp=new Sg({client:this._client});lsp=new Cg({client:this._client});formatter=new wg({client:this._client});tui=new Eg({client:this._client});auth=new xg({client:this._client});event=new Dg({client:this._client})};function kg(e,t){if(e)return t&&(e===t||e===encodeURIComponent(t))?t:e}function Ag(e,t){if(e.method!==`GET`&&e.method!==`HEAD`)return e;let n=kg(e.headers.get(`x-opencode-directory`),t);if(!n)return e;let r=new URL(e.url);r.searchParams.has(`directory`)||r.searchParams.set(`directory`,n);let i=new Request(r,e);return i.headers.delete(`x-opencode-directory`),i}function jg(e){if(!e?.fetch){let t=e=>(e.timeout=!1,fetch(e));e={...e,fetch:t}}e?.directory&&(e.headers={...e.headers,"x-opencode-directory":encodeURIComponent(e.directory)});let t=rg(e);return t.interceptors.request.use(t=>Ag(t,e?.directory)),t.interceptors.error.use(o),new Og({client:t})}var Mg=/* @__PURE__ */ r(s(),1);function Ng(e){if(e.exitCode===null&&e.signalCode===null){if(process.platform===`win32`&&e.pid){let t=pr(`taskkill`,[`/pid`,String(e.pid),`/T`,`/F`],{windowsHide:!0});if(!t.error&&t.status===0)return}e.kill()}}function Pg(e,t,n){if(!t)return()=>{};let r=()=>{i(),Ng(e),n?.()},i=()=>{t.removeEventListener(`abort`,r),e.off(`exit`,i),e.off(`error`,i)};return t.addEventListener(`abort`,r,{once:!0}),e.on(`exit`,i),e.on(`error`,i),t.aborted&&r(),i}async function Fg(e){e=Object.assign({hostname:`127.0.0.1`,port:4096,timeout:5e3},e??{});let t=[`serve`,`--hostname=${e.hostname}`,`--port=${e.port}`];e.config?.logLevel&&t.push(`--log-level=${e.config.logLevel}`);let n=(0,Mg.default)(`opencode`,t,{env:{...process.env,OPENCODE_CONFIG_CONTENT:JSON.stringify(e.config??{})}}),r=()=>{};return{url:await new Promise((t,i)=>{let a=setTimeout(()=>{r(),Ng(n),i(/* @__PURE__ */ Error(`Timeout waiting for server to start after ${e.timeout}ms`))},e.timeout),o=``,s=!1;n.stdout?.on(`data`,e=>{if(s)return;o+=e.toString();let c=o.split(` -`);for(let e of c)if(e.startsWith(`opencode server listening`)){let o=e.match(/on\s+(https?:\/\/[^\s]+)/);if(!o){r(),Ng(n),clearTimeout(a),i(/* @__PURE__ */ Error(`Failed to parse server url from output: ${e}`));return}clearTimeout(a),s=!0,t(o[1]);return}}),n.stderr?.on(`data`,e=>{o+=e.toString()}),n.on(`exit`,e=>{clearTimeout(a);let t=`Server exited with code ${e}`;o.trim()&&(t+=`\nServer output: ${o}`),i(Error(t))}),n.on(`error`,e=>{clearTimeout(a),i(e)}),r=Pg(n,e.signal,()=>{clearTimeout(a),i(e.signal?.reason)})}),close(){r(),Ng(n)}}}async function Ig(e){let t=await Fg({...e});return{client:jg({baseUrl:t.url}),server:t}}async function Lg(e){if(e<0||!Number.isFinite(e))throw Error(`Invalid sleep duration: ${e}`);return new Promise(t=>setTimeout(t,e))}const Rg=18e5,zg=5e3,Bg={providerID:`opencode`,modelID:`big-pickle`},Vg=`1.19.4+harness.5bde2635`,Hg=`3.27.2`,Ug=`fro-bot-state`,Wg=`opencode-tools-v2`,Gg=6e5,Kg=`fro-bot-dedup-v1`;async function qg(e,t){let n=[];try{let e=vs(_n.env);for(let t of Object.keys(_n.env))if(!(t in e)){let e=_n.env[t];e!==void 0&&(n.push([t,e]),delete _n.env[t])}t.info(`Scrubbed agent env for spawn`,{removedCount:n.length})}catch(e){for(let[e,t]of n)_n.env[e]=t;throw e}try{return await e()}finally{for(let[e,t]of n)_n.env[e]=t}}function Jg(e,t){return Bn.connect({host:e,port:t})}async function Yg(e,t,n,r=Jg){return new Promise(i=>{let a=!1,o=r(e,t),s=e=>{a||(a=!0,o.destroy(),o.removeAllListeners(),i(e))};o.setTimeout(n,()=>s(!0)),o.once(`connect`,()=>s(!0)),o.once(`error`,()=>s(!1))})}async function Xg(e,t=5e3,n=100,r=Jg){let i,a;try{let t=new URL(e);i=t.hostname,a=Number(t.port)}catch{return{quiesced:!1}}if(!Number.isInteger(a)||a<=0||a>65535)return{quiesced:!1};let o=Date.now()+t;do{if(!await Yg(i,a,n,r))return{quiesced:!0};await Lg(n)}while(Date.now(){let n=Bn.createServer();n.once(`error`,t),n.listen(0,`127.0.0.1`,()=>{let r=n.address();if(r===null||typeof r==`string`){n.close(),t(/* @__PURE__ */ Error(`Failed to determine ephemeral port`));return}let{port:i}=r;n.close(n=>{n==null?e(i):t(n)})})})}async function Qg(e,t,n,r,i){let a=AbortSignal.timeout(r);try{let r=await e.session.list({query:{directory:t},signal:AbortSignal.any([n,a])});return r.error!=null&&i.debug(`OpenCode readiness probe answered with an error body (server is ready)`,{error:us(r.error)}),{kind:`ready`}}catch(e){return n.aborted?{kind:`aborted`}:a.aborted?{kind:`timeout`}:{kind:`transport`,error:e}}}function $g(e){let t=_n.env.OPENCODE_CLIENT,n=_n.env.OPENCODE_ENABLE_QUESTION_TOOL,r=t!==void 0&&t!==``&&t!==`fro-bot-action`,i=n!==void 0&&n!==``;_n.env.OPENCODE_CLIENT=`fro-bot-action`,delete _n.env.OPENCODE_ENABLE_QUESTION_TOOL,(r||i)&&e.warning(`OPENCODE_CLIENT / OPENCODE_ENABLE_QUESTION_TOOL overridden: the OpenCode question tool is disabled for CI runs because nobody can answer it`,{overriddenClient:r,overriddenEnableQuestionTool:i})}async function e_(e,t,n,r=zg,i=6e4,a={}){let o=Date.now(),s=null,c;try{let l=await Zg(),u=`http://127.0.0.1:${l}`;_n.env.FRO_BOT_OPENCODE_URL=u,(_n.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER===void 0||_n.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER===``)&&(_n.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER=`true`),(_n.env.OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS===void 0||_n.env.OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS===``)&&(_n.env.OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=`true`),$g(t);let d={signal:e,hostname:`127.0.0.1`,port:l,timeout:r,...a.config===void 0?{}:{config:a.config}},f=Date.now(),p=await qg(async()=>Ig(d),t);s=Date.now()-f;let{client:m,server:h}=p;if(c=h,h.url!==u)return h.close(),G(/* @__PURE__ */ Error(`OpenCode server URL mismatch: pinned ${u} but server bound to ${h.url}`));let g=Date.now(),v=await Qg(m,n,e,i,t);if(v.kind===`transport`&&(t.warning(`OpenCode readiness probe failed (retrying once)`,{error:os(v.error)}),v=await Qg(m,n,e,i,t)),v.kind!==`ready`){let n=e.aborted,r=Date.now()-g;t.warning(`OpenCode readiness probe failed`,{outcome:v.kind,error:v.kind===`transport`?os(v.error):void 0,readinessTimeoutMs:i,readinessMs:r,cancelledByOuterDeadline:n}),h.close();let a=await Xg(h.url);return t.debug(`OpenCode server quiesced after readiness-probe failure`,{quiesced:a.quiesced}),v.kind===`transport`?G(/* @__PURE__ */ Error(`OpenCode server is listening but the readiness request failed twice against the local server: ${os(v.error)}`)):G(Error(n?`OpenCode server bootstrap cancelled by the execution deadline during the readiness probe`:`OpenCode server is listening but did not answer an instance-scoped request within ${i}ms per attempt (${r}ms total probe time) — instance bootstrap is blocked`))}let y=Date.now()-g,b=Date.now()-o;return t.debug(`OpenCode server bootstrapped`,{url:h.url,timeoutMs:r,budgetedMs:s,readinessMs:y,elapsedMs:b}),as({client:m,server:h,shutdown:async()=>(h.close(),Xg(h.url))})}catch(e){let n=Date.now()-o,i=os(e);t.warning(`Failed to bootstrap OpenCode server`,{error:i,timeoutMs:r,budgetedMs:s,elapsedMs:n});try{c?.close()}catch{}return G(/* @__PURE__ */ Error(`Server bootstrap failed: ${i}`))}}function t_(e){return e.trim().replace(/^v(?=\d)/,``).replace(/^(\d+\.\d+\.\d+)-harness\./,`$1+harness.`)}async function n_(e,t){let{logger:n,opencodeVersion:r}=e,i=_n.env.OPENCODE_PATH??null,a=await t.verifyOpenCodeAvailable(i,n);if(a.available&&a.version!=null){if(t_(a.version)===t_(r))return n.info(`OpenCode already available`,{version:a.version}),{path:i??`opencode`,version:a.version,didSetup:!1};let e={foundVersion:a.version,requestedVersion:r,source:i===null?`PATH`:`OPENCODE_PATH`};i===null?n.info(`Existing OpenCode does not match the pinned version, running auto-setup`,e):n.warning(`Existing OpenCode does not match the pinned version, running auto-setup`,e)}else n.info(`OpenCode not found, running auto-setup`,{requestedVersion:r});let o={opencodeVersion:r,authJson:e.authJson,appId:null,privateKey:null,opencodeConfig:e.opencodeConfig,systematicConfig:e.systematicConfig,systematicVersion:e.systematicVersion,credential:e.credential},s=await t.runSetup(o,e.githubToken);if(s==null)throw Error(`Auto-setup failed: runSetup returned null`);return t.addToPath(s.opencodePath),_n.env.OPENCODE_PATH=s.opencodeBinaryPath,n.info(`Auto-setup completed`,{version:s.opencodeVersion,path:s.opencodePath,binaryPath:s.opencodeBinaryPath}),{path:s.opencodeBinaryPath,version:s.opencodeVersion,didSetup:!0}}async function r_(e,t,n){try{let r=await c({baseUrl:e}).session.update({sessionID:t,time:{archived:Date.now()}});return r.error==null?(n.debug(`Archived session via SDK`,{sessionId:t}),!0):(n.warning(`SDK session archive failed`,{sessionId:t,error:us(r.error)}),!1)}catch(e){return n.warning(`SDK session archive failed`,{sessionId:t,error:os(e)}),!1}}const i_=e=>typeof e==`object`&&!!e,a_=e=>typeof e==`string`?e:null,o_=e=>typeof e==`number`?e:null;function s_(e){if(Array.isArray(e))return e.filter(i_).map(e=>({file:a_(e.file)??``,additions:o_(e.additions)??0,deletions:o_(e.deletions)??0}))}function c_(e){return{id:e.id,version:e.version,projectID:e.projectID,directory:e.directory,parentID:e.parentID,title:e.title,time:{created:e.time.created,updated:e.time.updated,compacting:e.time.compacting,archived:e.time.archived},summary:e.summary==null?void 0:{additions:e.summary.additions,deletions:e.summary.deletions,files:e.summary.files,diffs:s_(e.summary.diffs)},share:e.share?.url==null?void 0:{url:e.share.url},permission:e.permission==null?void 0:{rules:e.permission.rules},revert:e.revert==null?void 0:{messageID:e.revert.messageID,partID:e.revert.partID,snapshot:e.revert.snapshot,diff:e.revert.diff}}}function l_(e){if(!Array.isArray(e))return[];let t=[];for(let n of e){if(!i_(n))continue;let e=a_(n.content),r=a_(n.status),i=a_(n.priority);e!=null&&r!=null&&i!=null&&t.push({...a_(n.id)==null?{}:{id:a_(n.id)??``},content:e,status:r===`pending`||r===`in_progress`||r===`completed`||r===`cancelled`?r:`pending`,priority:i===`high`||i===`medium`||i===`low`?i:`medium`})}return t}function u_(e){return e.status===`running`?{status:`running`,input:e.input,time:{start:e.time.start}}:e.status===`error`?{status:`error`,input:e.input,error:e.error,time:{start:e.time.start,end:e.time.end}}:e.status===`pending`?{status:`pending`}:{status:`completed`,input:e.input,output:e.output,title:e.title,metadata:e.metadata,time:{start:e.time.start,end:e.time.end,compacted:e.time.compacted},attachments:void 0}}function d_(e){let t={id:e.id,sessionID:e.sessionID,messageID:e.messageID};if(e.type===`text`)return{...t,type:`text`,text:e.text,synthetic:e.synthetic,ignored:e.ignored,time:e.time,metadata:e.metadata};if(e.type===`reasoning`)return{...t,type:`reasoning`,reasoning:e.reasoning??e.text,time:e.time};if(e.type===`tool`)return{...t,type:`tool`,callID:e.callID,tool:e.tool,state:u_(e.state),metadata:e.metadata};if(e.type!==`step-finish`)return{...t,type:`text`,text:`text`in e?e.text:``};let n=e;return{...t,type:`step-finish`,reason:n.reason,snapshot:n.snapshot,cost:n.cost,tokens:{input:n.tokens.input,output:n.tokens.output,reasoning:n.tokens.reasoning,cache:{read:n.tokens.cache.read,write:n.tokens.cache.write}}}}function f_(e){if(e.role===`user`){let t=e;return{id:t.id,sessionID:t.sessionID,role:`user`,time:{created:t.time.created},summary:t.summary==null?void 0:{title:t.summary.title,body:t.summary.body,diffs:s_(t.summary.diffs)??[]},agent:t.agent,model:{providerID:t.model.providerID,modelID:t.model.modelID},system:t.system,tools:t.tools,variant:t.variant}}let t=e;return{id:t.id,sessionID:t.sessionID,role:`assistant`,time:{created:t.time.created,completed:t.time.completed},parentID:t.parentID,modelID:t.modelID,providerID:t.providerID,mode:t.mode,agent:t.agent??``,path:{cwd:t.path.cwd,root:t.path.root},summary:t.summary,cost:t.cost,tokens:{input:t.tokens.input,output:t.tokens.output,reasoning:t.tokens.reasoning,cache:{read:t.tokens.cache.read,write:t.tokens.cache.write}},finish:t.finish,error:t.error?{name:t.error.name,message:a_(t.error.data.message)??``}:void 0}}function p_(e){return[...e.map(e=>{let t=f_(`info`in e?e.info:e),n=`parts`in e?e.parts.map(d_):void 0;return n==null||n.length===0?t:{...t,parts:n}})].sort((e,t)=>e.time.created-t.time.created)}async function m_(e,t,n){let r=await e.session.list({query:{directory:t}});return r.error==null&&r.data!=null?Array.isArray(r.data)?r.data.map(c_):(n.warning(`SDK session list returned a non-array payload`,{source:`listSessionsForProject`,type:typeof r.data}),[]):(n.warning(`SDK session list failed`,{source:`listSessionsForProject`,error:os(r.error)}),[])}async function h_(e,t,n){let r=await e.session.get({path:{id:t}});return r.error!=null||r.data==null?(n.warning(`SDK session get failed`,{error:os(r.error)}),null):c_(r.data)}async function g_(e,t,n){let r=await e.session.messages({path:{id:t}});return r.error==null&&r.data!=null?Array.isArray(r.data)?p_(r.data):(n.warning(`SDK session messages returned a non-array payload`,{type:typeof r.data}),[]):(n.warning(`SDK session messages failed`,{error:os(r.error)}),[])}async function __(e,t,n){let r=await e.session.todos({path:{id:t}});return r.error==null&&r.data!=null?Array.isArray(r.data)?l_(r.data):(n.warning(`SDK session todos returned a non-array payload`,{type:typeof r.data}),[]):(n.warning(`SDK session todos failed`,{error:os(r.error)}),[])}async function v_(e,t,n,r){let i=await e.session.list({query:{directory:t,start:n,roots:!0,limit:10}});if(i.error!=null||i.data==null)return r.warning(`SDK session list failed`,{source:`findLatestSession`,error:os(i.error)}),null;if(!Array.isArray(i.data))return r.warning(`SDK session list returned a non-array payload`,{source:`findLatestSession`,type:typeof i.data}),null;if(i.data.length===0)return null;let a=i.data.map(c_).reduce((e,t)=>t.time.created>e.time.created?t:e);return{projectID:a.projectID,session:a}}async function y_(e,t,n){let r=await e.session.delete({path:{id:t}});r.error==null?n.debug(`Deleted session via SDK`,{sessionID:t}):n.warning(`SDK session delete failed`,{sessionID:t,error:os(r.error)})}async function b_(e,t,n,r){let{limit:i,fromDate:a,toDate:o}=n;r.debug(`Listing sessions`,{directory:t,limit:i});let s=[...(await m_(e,t,r)).filter(e=>!(e.parentID!=null||e.time.archived!=null||e.time.compacting!=null||a!=null&&e.time.createdo.getTime()))].sort((e,t)=>t.time.updated-e.time.updated),c=[],l=i==null?s:s.slice(0,i);for(let t of l){let n=await g_(e,t.id,r),i=x_(n);c.push({id:t.id,projectID:t.projectID,directory:t.directory,title:t.title,createdAt:t.time.created,updatedAt:t.time.updated,messageCount:n.length,agents:i,isChild:!1})}return r.info(`Listed sessions`,{count:c.length,directory:t}),c}function x_(e){let t=/* @__PURE__ */ new Set;for(let n of e)n.agent!=null&&t.add(n.agent);return[...t]}async function S_(e,t,n,r,i){let{limit:a=20,caseSensitive:o=!1,sessionId:s,excludeSessionIds:c=[]}=r,l=new Set(c);i.debug(`Searching sessions`,{query:e,directory:n,limit:a,caseSensitive:o});let u=o?e:e.toLowerCase(),d=[],f=0;if(s!=null){if(l.has(s))return d;let e=await C_(t,s,u,o,i);return e.length>0&&d.push({sessionId:s,matches:e.slice(0,a)}),d}let p=(await b_(t,n,{},i)).filter(e=>l.has(e.id)===!1);for(let e of p){if(f>=a)break;let n=await C_(t,e.id,u,o,i);if(n.length>0){let t=a-f;d.push({sessionId:e.id,matches:n.slice(0,t)}),f+=Math.min(n.length,t)}}return i.info(`Session search complete`,{query:e,resultCount:d.length,totalMatches:f}),d}async function C_(e,t,n,r,i){let a=await g_(e,t,i),o=[];for(let e of a){let t=e.parts??[];for(let i of t){let t=w_(i);if(t==null)continue;let a=r?t:t.toLowerCase();if(a.includes(n)){let r=a.indexOf(n),s=Math.max(0,r-50),c=Math.min(t.length,r+n.length+50),l=t.slice(s,c);o.push({messageId:e.id,partId:i.id,excerpt:`...${l}...`,role:e.role,agent:e.agent})}}}return o}function w_(e){switch(e.type){case`text`:return e.text;case`reasoning`:return e.reasoning;case`tool`:return e.state.status===`completed`?`${e.tool}: ${e.state.output}`:null;case`step-finish`:return null}}async function T_(e,t,n){let r=await h_(e,t,n);if(r==null)return null;let i=await g_(e,t,n),a=x_(i),o=await __(e,t,n);return{session:r,messageCount:i.length,agents:a,hasTodos:o.length>0,todoCount:o.length,completedTodos:o.filter(e=>e.status===`completed`).length}}const E_=`opencode.db`,D_=`${E_}-wal`,O_=`${E_}-shm`,k_=[E_,D_,O_],A_=[E_],j_=`opencode.db`,M_=`${j_}-wal`,N_=`${j_}-shm`,P_=[j_,M_,N_],F_=[j_];function I_(e){return e===`v2`?{main:j_,wal:M_,shm:N_,family:P_,transportable:F_}:{main:E_,wal:D_,shm:O_,family:k_,transportable:A_}}function L_(){let e=_n.env.XDG_DATA_HOME??tr.join(mr.homedir(),`.local`,`share`);return tr.join(e,`opencode`,E_)}async function R_(e){if(e!=null)return B_(e,`1.2.0`)>=0;try{return await $n.access(L_()),!0}catch{return!1}}function z_(e){let t=e.split(`+`)[0]??e;return t.split(`-`)[0]??t}function B_(e,t){let n=z_(e).split(`.`).map(Number),r=z_(t).split(`.`).map(Number);for(let e=0;e<3;e++){let t=(n[e]??0)-(r[e]??0);if(t!==0)return t}return 0}const V_={debug:()=>{},info:()=>{},warning:()=>{},error:()=>{}};function H_(e){return`session store unavailable: ${e}`}function U_(e){return new Date(e).toISOString()}function W_(e){return typeof e==`string`&&e.length>0?e:void 0}function G_(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function K_(e){return typeof e==`boolean`?e:void 0}function q_(e){if(e==null)return;let t=new Date(e);return Number.isNaN(t.getTime())?void 0:t}function J_(e){let t=q_(e);if(t==null)return;let n=new Date(t);return n.setUTCHours(23,59,59,999),n}function Y_(e){return e==null||e<1?void 0:e}function X_(e){let t=(e.parts??[]).map(e=>w_(e)).filter(e=>e!=null).join(` `);return t.length>0?`[${e.role}] ${t}`:`[${e.role}] (no content)`}function Z_(e){let t=[],n=0,r=0;for(let i of e){let e=` ${X_(i)}`;if(n+e.length>48e3)break;t.push(e),n+=e.length,r+=1}return r`${e.id} ${e.title||`(untitled)`} updated ${U_(e.updatedAt)}`).join(` +`);for(let e of c)if(e.startsWith(`opencode server listening`)){let o=e.match(/on\s+(https?:\/\/[^\s]+)/);if(!o){r(),Ng(n),clearTimeout(a),i(/* @__PURE__ */ Error(`Failed to parse server url from output: ${e}`));return}clearTimeout(a),s=!0,t(o[1]);return}}),n.stderr?.on(`data`,e=>{o+=e.toString()}),n.on(`exit`,e=>{clearTimeout(a);let t=`Server exited with code ${e}`;o.trim()&&(t+=`\nServer output: ${o}`),i(Error(t))}),n.on(`error`,e=>{clearTimeout(a),i(e)}),r=Pg(n,e.signal,()=>{clearTimeout(a),i(e.signal?.reason)})}),close(){r(),Ng(n)}}}async function Ig(e){let t=await Fg({...e});return{client:jg({baseUrl:t.url}),server:t}}async function Lg(e){if(e<0||!Number.isFinite(e))throw Error(`Invalid sleep duration: ${e}`);return new Promise(t=>setTimeout(t,e))}const Rg=18e5,zg=5e3,Bg={providerID:`opencode`,modelID:`big-pickle`},Vg=`1.19.4+harness.5bde2635`,Hg=`3.28.0`,Ug=`fro-bot-state`,Wg=`opencode-tools-v2`,Gg=6e5,Kg=`fro-bot-dedup-v1`;async function qg(e,t){let n=[];try{let e=vs(_n.env);for(let t of Object.keys(_n.env))if(!(t in e)){let e=_n.env[t];e!==void 0&&(n.push([t,e]),delete _n.env[t])}t.info(`Scrubbed agent env for spawn`,{removedCount:n.length})}catch(e){for(let[e,t]of n)_n.env[e]=t;throw e}try{return await e()}finally{for(let[e,t]of n)_n.env[e]=t}}function Jg(e,t){return Bn.connect({host:e,port:t})}async function Yg(e,t,n,r=Jg){return new Promise(i=>{let a=!1,o=r(e,t),s=e=>{a||(a=!0,o.destroy(),o.removeAllListeners(),i(e))};o.setTimeout(n,()=>s(!0)),o.once(`connect`,()=>s(!0)),o.once(`error`,()=>s(!1))})}async function Xg(e,t=5e3,n=100,r=Jg){let i,a;try{let t=new URL(e);i=t.hostname,a=Number(t.port)}catch{return{quiesced:!1}}if(!Number.isInteger(a)||a<=0||a>65535)return{quiesced:!1};let o=Date.now()+t;do{if(!await Yg(i,a,n,r))return{quiesced:!0};await Lg(n)}while(Date.now(){let n=Bn.createServer();n.once(`error`,t),n.listen(0,`127.0.0.1`,()=>{let r=n.address();if(r===null||typeof r==`string`){n.close(),t(/* @__PURE__ */ Error(`Failed to determine ephemeral port`));return}let{port:i}=r;n.close(n=>{n==null?e(i):t(n)})})})}async function Qg(e,t,n,r,i){let a=AbortSignal.timeout(r);try{let r=await e.session.list({query:{directory:t},signal:AbortSignal.any([n,a])});return r.error!=null&&i.debug(`OpenCode readiness probe answered with an error body (server is ready)`,{error:us(r.error)}),{kind:`ready`}}catch(e){return n.aborted?{kind:`aborted`}:a.aborted?{kind:`timeout`}:{kind:`transport`,error:e}}}function $g(e){let t=_n.env.OPENCODE_CLIENT,n=_n.env.OPENCODE_ENABLE_QUESTION_TOOL,r=t!==void 0&&t!==``&&t!==`fro-bot-action`,i=n!==void 0&&n!==``;_n.env.OPENCODE_CLIENT=`fro-bot-action`,delete _n.env.OPENCODE_ENABLE_QUESTION_TOOL,(r||i)&&e.warning(`OPENCODE_CLIENT / OPENCODE_ENABLE_QUESTION_TOOL overridden: the OpenCode question tool is disabled for CI runs because nobody can answer it`,{overriddenClient:r,overriddenEnableQuestionTool:i})}async function e_(e,t,n,r=zg,i=6e4,a={}){let o=Date.now(),s=null,c;try{let l=await Zg(),u=`http://127.0.0.1:${l}`;_n.env.FRO_BOT_OPENCODE_URL=u,(_n.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER===void 0||_n.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER===``)&&(_n.env.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER=`true`),(_n.env.OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS===void 0||_n.env.OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS===``)&&(_n.env.OPENCODE_EXPERIMENTAL_BACKGROUND_SUBAGENTS=`true`),$g(t);let d={signal:e,hostname:`127.0.0.1`,port:l,timeout:r,...a.config===void 0?{}:{config:a.config}},f=Date.now(),p=await qg(async()=>Ig(d),t);s=Date.now()-f;let{client:m,server:h}=p;if(c=h,h.url!==u)return h.close(),G(/* @__PURE__ */ Error(`OpenCode server URL mismatch: pinned ${u} but server bound to ${h.url}`));let g=Date.now(),v=await Qg(m,n,e,i,t);if(v.kind===`transport`&&(t.warning(`OpenCode readiness probe failed (retrying once)`,{error:os(v.error)}),v=await Qg(m,n,e,i,t)),v.kind!==`ready`){let n=e.aborted,r=Date.now()-g;t.warning(`OpenCode readiness probe failed`,{outcome:v.kind,error:v.kind===`transport`?os(v.error):void 0,readinessTimeoutMs:i,readinessMs:r,cancelledByOuterDeadline:n}),h.close();let a=await Xg(h.url);return t.debug(`OpenCode server quiesced after readiness-probe failure`,{quiesced:a.quiesced}),v.kind===`transport`?G(/* @__PURE__ */ Error(`OpenCode server is listening but the readiness request failed twice against the local server: ${os(v.error)}`)):G(Error(n?`OpenCode server bootstrap cancelled by the execution deadline during the readiness probe`:`OpenCode server is listening but did not answer an instance-scoped request within ${i}ms per attempt (${r}ms total probe time) — instance bootstrap is blocked`))}let y=Date.now()-g,b=Date.now()-o;return t.debug(`OpenCode server bootstrapped`,{url:h.url,timeoutMs:r,budgetedMs:s,readinessMs:y,elapsedMs:b}),as({client:m,server:h,shutdown:async()=>(h.close(),Xg(h.url))})}catch(e){let n=Date.now()-o,i=os(e);t.warning(`Failed to bootstrap OpenCode server`,{error:i,timeoutMs:r,budgetedMs:s,elapsedMs:n});try{c?.close()}catch{}return G(/* @__PURE__ */ Error(`Server bootstrap failed: ${i}`))}}function t_(e){return e.trim().replace(/^v(?=\d)/,``).replace(/^(\d+\.\d+\.\d+)-harness\./,`$1+harness.`)}async function n_(e,t){let{logger:n,opencodeVersion:r}=e,i=_n.env.OPENCODE_PATH??null,a=await t.verifyOpenCodeAvailable(i,n);if(a.available&&a.version!=null){if(t_(a.version)===t_(r))return n.info(`OpenCode already available`,{version:a.version}),{path:i??`opencode`,version:a.version,didSetup:!1};let e={foundVersion:a.version,requestedVersion:r,source:i===null?`PATH`:`OPENCODE_PATH`};i===null?n.info(`Existing OpenCode does not match the pinned version, running auto-setup`,e):n.warning(`Existing OpenCode does not match the pinned version, running auto-setup`,e)}else n.info(`OpenCode not found, running auto-setup`,{requestedVersion:r});let o={opencodeVersion:r,authJson:e.authJson,appId:null,privateKey:null,opencodeConfig:e.opencodeConfig,systematicConfig:e.systematicConfig,systematicVersion:e.systematicVersion,credential:e.credential},s=await t.runSetup(o,e.githubToken);if(s==null)throw Error(`Auto-setup failed: runSetup returned null`);return t.addToPath(s.opencodePath),_n.env.OPENCODE_PATH=s.opencodeBinaryPath,n.info(`Auto-setup completed`,{version:s.opencodeVersion,path:s.opencodePath,binaryPath:s.opencodeBinaryPath}),{path:s.opencodeBinaryPath,version:s.opencodeVersion,didSetup:!0}}async function r_(e,t,n){try{let r=await c({baseUrl:e}).session.update({sessionID:t,time:{archived:Date.now()}});return r.error==null?(n.debug(`Archived session via SDK`,{sessionId:t}),!0):(n.warning(`SDK session archive failed`,{sessionId:t,error:us(r.error)}),!1)}catch(e){return n.warning(`SDK session archive failed`,{sessionId:t,error:os(e)}),!1}}const i_=e=>typeof e==`object`&&!!e,a_=e=>typeof e==`string`?e:null,o_=e=>typeof e==`number`?e:null;function s_(e){if(Array.isArray(e))return e.filter(i_).map(e=>({file:a_(e.file)??``,additions:o_(e.additions)??0,deletions:o_(e.deletions)??0}))}function c_(e){return{id:e.id,version:e.version,projectID:e.projectID,directory:e.directory,parentID:e.parentID,title:e.title,time:{created:e.time.created,updated:e.time.updated,compacting:e.time.compacting,archived:e.time.archived},summary:e.summary==null?void 0:{additions:e.summary.additions,deletions:e.summary.deletions,files:e.summary.files,diffs:s_(e.summary.diffs)},share:e.share?.url==null?void 0:{url:e.share.url},permission:e.permission==null?void 0:{rules:e.permission.rules},revert:e.revert==null?void 0:{messageID:e.revert.messageID,partID:e.revert.partID,snapshot:e.revert.snapshot,diff:e.revert.diff}}}function l_(e){if(!Array.isArray(e))return[];let t=[];for(let n of e){if(!i_(n))continue;let e=a_(n.content),r=a_(n.status),i=a_(n.priority);e!=null&&r!=null&&i!=null&&t.push({...a_(n.id)==null?{}:{id:a_(n.id)??``},content:e,status:r===`pending`||r===`in_progress`||r===`completed`||r===`cancelled`?r:`pending`,priority:i===`high`||i===`medium`||i===`low`?i:`medium`})}return t}function u_(e){return e.status===`running`?{status:`running`,input:e.input,time:{start:e.time.start}}:e.status===`error`?{status:`error`,input:e.input,error:e.error,time:{start:e.time.start,end:e.time.end}}:e.status===`pending`?{status:`pending`}:{status:`completed`,input:e.input,output:e.output,title:e.title,metadata:e.metadata,time:{start:e.time.start,end:e.time.end,compacted:e.time.compacted},attachments:void 0}}function d_(e){let t={id:e.id,sessionID:e.sessionID,messageID:e.messageID};if(e.type===`text`)return{...t,type:`text`,text:e.text,synthetic:e.synthetic,ignored:e.ignored,time:e.time,metadata:e.metadata};if(e.type===`reasoning`)return{...t,type:`reasoning`,reasoning:e.reasoning??e.text,time:e.time};if(e.type===`tool`)return{...t,type:`tool`,callID:e.callID,tool:e.tool,state:u_(e.state),metadata:e.metadata};if(e.type!==`step-finish`)return{...t,type:`text`,text:`text`in e?e.text:``};let n=e;return{...t,type:`step-finish`,reason:n.reason,snapshot:n.snapshot,cost:n.cost,tokens:{input:n.tokens.input,output:n.tokens.output,reasoning:n.tokens.reasoning,cache:{read:n.tokens.cache.read,write:n.tokens.cache.write}}}}function f_(e){if(e.role===`user`){let t=e;return{id:t.id,sessionID:t.sessionID,role:`user`,time:{created:t.time.created},summary:t.summary==null?void 0:{title:t.summary.title,body:t.summary.body,diffs:s_(t.summary.diffs)??[]},agent:t.agent,model:{providerID:t.model.providerID,modelID:t.model.modelID},system:t.system,tools:t.tools,variant:t.variant}}let t=e;return{id:t.id,sessionID:t.sessionID,role:`assistant`,time:{created:t.time.created,completed:t.time.completed},parentID:t.parentID,modelID:t.modelID,providerID:t.providerID,mode:t.mode,agent:t.agent??``,path:{cwd:t.path.cwd,root:t.path.root},summary:t.summary,cost:t.cost,tokens:{input:t.tokens.input,output:t.tokens.output,reasoning:t.tokens.reasoning,cache:{read:t.tokens.cache.read,write:t.tokens.cache.write}},finish:t.finish,error:t.error?{name:t.error.name,message:a_(t.error.data.message)??``}:void 0}}function p_(e){return[...e.map(e=>{let t=f_(`info`in e?e.info:e),n=`parts`in e?e.parts.map(d_):void 0;return n==null||n.length===0?t:{...t,parts:n}})].sort((e,t)=>e.time.created-t.time.created)}async function m_(e,t,n){let r=await e.session.list({query:{directory:t}});return r.error==null&&r.data!=null?Array.isArray(r.data)?r.data.map(c_):(n.warning(`SDK session list returned a non-array payload`,{source:`listSessionsForProject`,type:typeof r.data}),[]):(n.warning(`SDK session list failed`,{source:`listSessionsForProject`,error:os(r.error)}),[])}async function h_(e,t,n){let r=await e.session.get({path:{id:t}});return r.error!=null||r.data==null?(n.warning(`SDK session get failed`,{error:os(r.error)}),null):c_(r.data)}async function g_(e,t,n){let r=await e.session.messages({path:{id:t}});return r.error==null&&r.data!=null?Array.isArray(r.data)?p_(r.data):(n.warning(`SDK session messages returned a non-array payload`,{type:typeof r.data}),[]):(n.warning(`SDK session messages failed`,{error:os(r.error)}),[])}async function __(e,t,n){let r=await e.session.todos({path:{id:t}});return r.error==null&&r.data!=null?Array.isArray(r.data)?l_(r.data):(n.warning(`SDK session todos returned a non-array payload`,{type:typeof r.data}),[]):(n.warning(`SDK session todos failed`,{error:os(r.error)}),[])}async function v_(e,t,n,r){let i=await e.session.list({query:{directory:t,start:n,roots:!0,limit:10}});if(i.error!=null||i.data==null)return r.warning(`SDK session list failed`,{source:`findLatestSession`,error:os(i.error)}),null;if(!Array.isArray(i.data))return r.warning(`SDK session list returned a non-array payload`,{source:`findLatestSession`,type:typeof i.data}),null;if(i.data.length===0)return null;let a=i.data.map(c_).reduce((e,t)=>t.time.created>e.time.created?t:e);return{projectID:a.projectID,session:a}}async function y_(e,t,n){let r=await e.session.delete({path:{id:t}});r.error==null?n.debug(`Deleted session via SDK`,{sessionID:t}):n.warning(`SDK session delete failed`,{sessionID:t,error:os(r.error)})}async function b_(e,t,n,r){let{limit:i,fromDate:a,toDate:o}=n;r.debug(`Listing sessions`,{directory:t,limit:i});let s=[...(await m_(e,t,r)).filter(e=>!(e.parentID!=null||e.time.archived!=null||e.time.compacting!=null||a!=null&&e.time.createdo.getTime()))].sort((e,t)=>t.time.updated-e.time.updated),c=[],l=i==null?s:s.slice(0,i);for(let t of l){let n=await g_(e,t.id,r),i=x_(n);c.push({id:t.id,projectID:t.projectID,directory:t.directory,title:t.title,createdAt:t.time.created,updatedAt:t.time.updated,messageCount:n.length,agents:i,isChild:!1})}return r.info(`Listed sessions`,{count:c.length,directory:t}),c}function x_(e){let t=/* @__PURE__ */ new Set;for(let n of e)n.agent!=null&&t.add(n.agent);return[...t]}async function S_(e,t,n,r,i){let{limit:a=20,caseSensitive:o=!1,sessionId:s,excludeSessionIds:c=[]}=r,l=new Set(c);i.debug(`Searching sessions`,{query:e,directory:n,limit:a,caseSensitive:o});let u=o?e:e.toLowerCase(),d=[],f=0;if(s!=null){if(l.has(s))return d;let e=await C_(t,s,u,o,i);return e.length>0&&d.push({sessionId:s,matches:e.slice(0,a)}),d}let p=(await b_(t,n,{},i)).filter(e=>l.has(e.id)===!1);for(let e of p){if(f>=a)break;let n=await C_(t,e.id,u,o,i);if(n.length>0){let t=a-f;d.push({sessionId:e.id,matches:n.slice(0,t)}),f+=Math.min(n.length,t)}}return i.info(`Session search complete`,{query:e,resultCount:d.length,totalMatches:f}),d}async function C_(e,t,n,r,i){let a=await g_(e,t,i),o=[];for(let e of a){let t=e.parts??[];for(let i of t){let t=w_(i);if(t==null)continue;let a=r?t:t.toLowerCase();if(a.includes(n)){let r=a.indexOf(n),s=Math.max(0,r-50),c=Math.min(t.length,r+n.length+50),l=t.slice(s,c);o.push({messageId:e.id,partId:i.id,excerpt:`...${l}...`,role:e.role,agent:e.agent})}}}return o}function w_(e){switch(e.type){case`text`:return e.text;case`reasoning`:return e.reasoning;case`tool`:return e.state.status===`completed`?`${e.tool}: ${e.state.output}`:null;case`step-finish`:return null}}async function T_(e,t,n){let r=await h_(e,t,n);if(r==null)return null;let i=await g_(e,t,n),a=x_(i),o=await __(e,t,n);return{session:r,messageCount:i.length,agents:a,hasTodos:o.length>0,todoCount:o.length,completedTodos:o.filter(e=>e.status===`completed`).length}}const E_=`opencode.db`,D_=`${E_}-wal`,O_=`${E_}-shm`,k_=[E_,D_,O_],A_=[E_],j_=`opencode.db`,M_=`${j_}-wal`,N_=`${j_}-shm`,P_=[j_,M_,N_],F_=[j_];function I_(e){return e===`v2`?{main:j_,wal:M_,shm:N_,family:P_,transportable:F_}:{main:E_,wal:D_,shm:O_,family:k_,transportable:A_}}function L_(){let e=_n.env.XDG_DATA_HOME??tr.join(mr.homedir(),`.local`,`share`);return tr.join(e,`opencode`,E_)}async function R_(e){if(e!=null)return B_(e,`1.2.0`)>=0;try{return await $n.access(L_()),!0}catch{return!1}}function z_(e){let t=e.split(`+`)[0]??e;return t.split(`-`)[0]??t}function B_(e,t){let n=z_(e).split(`.`).map(Number),r=z_(t).split(`.`).map(Number);for(let e=0;e<3;e++){let t=(n[e]??0)-(r[e]??0);if(t!==0)return t}return 0}const V_={debug:()=>{},info:()=>{},warning:()=>{},error:()=>{}};function H_(e){return`session store unavailable: ${e}`}function U_(e){return new Date(e).toISOString()}function W_(e){return typeof e==`string`&&e.length>0?e:void 0}function G_(e){return typeof e==`number`&&Number.isFinite(e)?e:void 0}function K_(e){return typeof e==`boolean`?e:void 0}function q_(e){if(e==null)return;let t=new Date(e);return Number.isNaN(t.getTime())?void 0:t}function J_(e){let t=q_(e);if(t==null)return;let n=new Date(t);return n.setUTCHours(23,59,59,999),n}function Y_(e){return e==null||e<1?void 0:e}function X_(e){let t=(e.parts??[]).map(e=>w_(e)).filter(e=>e!=null).join(` `);return t.length>0?`[${e.role}] ${t}`:`[${e.role}] (no content)`}function Z_(e){let t=[],n=0,r=0;for(let i of e){let e=` ${X_(i)}`;if(n+e.length>48e3)break;t.push(e),n+=e.length,r+=1}return r`${e.id} ${e.title||`(untitled)`} updated ${U_(e.updatedAt)}`).join(` `)}catch(e){return H_(os(e))}}},read:{description:`Read a session: header, optional todos, and optional transcript.`,args:{session_id:am().describe(`The session id to read (required).`),include_todos:Fm().describe(`Include the session todo list.`).optional(),include_transcript:Fm().describe(`Include the message transcript.`).optional(),limit:jm().describe(`Maximum number of transcript messages to include.`).optional()},async execute(e){let n=t();if(`reason`in n)return H_(n.reason);let r=W_(e.session_id);if(r==null)return H_(`session_id is required`);try{let t=jg({baseUrl:n.baseUrl}),i=await h_(t,r,V_);if(i==null)return`session not found: ${r}`;let a=[`Session ${i.id}`,`Title: ${i.title||`(untitled)`}`,`Created: ${U_(i.time.created)}`,`Updated: ${U_(i.time.updated)}`];if(K_(e.include_todos)===!0){let e=await __(t,r,V_);if(a.push(``,`Todos:`),e.length===0)a.push(` (none)`);else for(let t of e)a.push(` [${t.status}] ${t.content}`)}if(K_(e.include_transcript)===!0){let n=Y_(G_(e.limit)),i=await g_(t,r,V_),o=n==null?i:i.slice(0,n);a.push(``,`Transcript:`),o.length===0?a.push(` (empty)`):a.push(...Z_(o))}return a.join(` `)}catch(e){return H_(os(e))}}},search:{description:`Search prior session content for matching text, optionally scoped to one session.`,args:{query:am().describe(`Text to search for (required).`),session_id:am().describe(`Restrict the search to a single session id.`).optional(),case_sensitive:Fm().describe(`Match case-sensitively.`).optional(),limit:jm().describe(`Maximum number of matches to return.`).optional()},async execute(e){let n=t();if(`reason`in n)return H_(n.reason);let r=W_(e.query);if(r==null)return H_(`query is required`);try{let t=jg({baseUrl:n.baseUrl}),i=_n.cwd(),a=W_(e.session_id);if(a!=null&&await h_(t,a,V_)==null)return`session not found: ${a}`;let o=await S_(r,t,i,{limit:Y_(G_(e.limit)),caseSensitive:K_(e.case_sensitive),sessionId:a},V_);if(o.length===0)return`No matches found.`;let s=[];for(let e of o){s.push(`Session ${e.sessionId}:`);for(let t of e.matches)s.push(` [${t.role}${t.agent==null?``:`/${t.agent}`}] ${t.excerpt}`)}return s.join(` `)}catch(e){return H_(os(e))}}},info:{description:`Summarize a session: id, title, timestamps, message and todo counts.`,args:{session_id:am().describe(`The session id to summarize (required).`)},async execute(e){let n=t();if(`reason`in n)return H_(n.reason);let r=W_(e.session_id);if(r==null)return H_(`session_id is required`);try{let e=await T_(jg({baseUrl:n.baseUrl}),r,V_);return e==null?`session not found: ${r}`:$_(e.session,{messageCount:e.messageCount,agents:e.agents,hasTodos:e.hasTodos,todoCount:e.todoCount,completedTodos:e.completedTodos})}catch(e){return H_(os(e))}}}}}function $_(e,t){return[`Session ${e.id}`,`Title: ${e.title||`(untitled)`}`,`Created: ${U_(e.time.created)}`,`Updated: ${U_(e.time.updated)}`,`Messages: ${t.messageCount}`,`Agents: ${t.agents.length>0?t.agents.join(`, `):`(none)`}`,`Todos: ${t.hasTodos?`${t.completedTodos}/${t.todoCount} completed`:`(none)`}`].join(` diff --git a/dist/main.js b/dist/main.js index 28a75e93dc..24e741a9e2 100644 --- a/dist/main.js +++ b/dist/main.js @@ -1,4 +1,4 @@ -import{o as e}from"./rolldown-runtime-Dlfrvzb7.js";import{$ as t,A as n,At as r,B as i,Bt as a,C as o,Ct as s,D as c,E as l,Et as u,F as d,Ft as f,G as p,Gt as m,Ht as h,I as g,It as _,J as v,Jt as y,K as b,Kt as x,L as S,Lt as C,M as w,Mt as T,N as E,Nt as D,O,Ot as k,P as A,Pt as ee,Q as j,Qt as M,R as N,Rt as P,S as te,St as F,T as ne,Tt as re,U as I,Ut as ie,V as ae,Vt as oe,W as L,Wt as se,X as ce,Xt as R,Y as le,Yt as ue,Z as de,Zt as fe,_ as pe,_t as me,a as he,an as z,at as ge,b as _e,bt as ve,c as ye,cn as be,ct as xe,d as Se,dn as Ce,dt as we,en as Te,et as Ee,fn as De,ft as Oe,g as ke,gt as Ae,h as B,hn as je,ht as Me,i as Ne,in as V,it as Pe,j as Fe,jt as Ie,k as Le,kt as Re,l as ze,ln as Be,lt as Ve,mn as He,mt as Ue,n as We,nn as Ge,nt as Ke,o as qe,on as Je,ot as Ye,p as Xe,pn as Ze,pt as Qe,q as $e,qt as H,r as et,rn as U,rt as tt,s as nt,sn as rt,st as it,t as at,tn as ot,tt as st,un as ct,ut as lt,v as ut,vt as dt,wt as ft,x as pt,xt as mt,y as ht,yt as gt,z as _t,zt as vt}from"./artifact-BIg7elxR.js";import W from"node:process";import*as yt from"os";import*as bt from"crypto";import*as G from"fs";import*as xt from"path";import{ok as St}from"assert";import*as Ct from"util";import{TextDecoder as wt}from"node:util";import{Buffer as Tt}from"node:buffer";import*as Et from"node:crypto";import{createHash as Dt}from"node:crypto";import{pathToFileURL as Ot}from"node:url";import*as K from"node:fs/promises";import{access as kt,chmod as At,lstat as jt,mkdir as Mt,mkdtemp as Nt,readdir as Pt,rm as Ft,stat as It,writeFile as Lt}from"node:fs/promises";import*as q from"node:path";import Rt,{dirname as zt,join as Bt,resolve as Vt,sep as Ht}from"node:path";import{constants as Ut}from"node:fs";import{spawn as Wt}from"node:child_process";import*as Gt from"node:os";import Kt,{homedir as qt,tmpdir as Jt}from"node:os";import*as Yt from"stream";const Xt={api_error:`API Error`,configuration:`Configuration Error`,context_overflow:`Context Overflow`,internal:`Internal Error`,llm_fetch_error:`LLM Fetch Error`,llm_timeout:`LLM Timeout`,model_not_found:`Model Not Found`,permission:`Permission Error`,provider_auth_error:`Provider Authentication Error`,quota_exceeded:`Quota Exceeded`,rate_limit:`Rate Limit`,validation:`Validation Error`};function Zt(e){return e.type===`rate_limit`?`:warning:`:e.type===`llm_timeout`?`:hourglass:`:e.type===`llm_fetch_error`||e.retryable?`:warning:`:`:x:`}function Qt(e){let t=Zt(e),n=Xt[e.type],r=[];return r.push(`${t} **${n}**`),r.push(``),r.push(e.message),e.details!=null&&(r.push(``),r.push(`> ${e.details}`)),e.suggestedAction!=null&&(r.push(``),r.push(`**Suggested action:** ${e.suggestedAction}`)),e.retryable&&(r.push(``),r.push(`_This error is retryable._`)),e.resetTime!=null&&(r.push(``),r.push(`_Rate limit resets at: ${e.resetTime.toISOString()}_`)),r.join(` +import{o as e}from"./rolldown-runtime-Dlfrvzb7.js";import{$ as t,A as n,At as r,B as i,Bt as a,C as o,Ct as s,D as c,E as l,Et as u,F as d,Ft as f,G as p,Gt as m,Ht as h,I as g,It as _,J as v,Jt as y,K as b,Kt as x,L as S,Lt as C,M as w,Mt as T,N as E,Nt as D,O,Ot as k,P as A,Pt as ee,Q as j,Qt as M,R as N,Rt as P,S as te,St as F,T as ne,Tt as re,U as I,Ut as ie,V as ae,Vt as oe,W as L,Wt as se,X as ce,Xt as R,Y as le,Yt as ue,Z as de,Zt as fe,_ as pe,_t as me,a as he,an as z,at as ge,b as _e,bt as ve,c as ye,cn as be,ct as xe,d as Se,dn as Ce,dt as we,en as Te,et as Ee,fn as De,ft as Oe,g as ke,gt as Ae,h as B,hn as je,ht as Me,i as Ne,in as V,it as Pe,j as Fe,jt as Ie,k as Le,kt as Re,l as ze,ln as Be,lt as Ve,mn as He,mt as Ue,n as We,nn as Ge,nt as Ke,o as qe,on as Je,ot as Ye,p as Xe,pn as Ze,pt as Qe,q as $e,qt as H,r as et,rn as U,rt as tt,s as nt,sn as rt,st as it,t as at,tn as ot,tt as st,un as ct,ut as lt,v as ut,vt as dt,wt as ft,x as pt,xt as mt,y as ht,yt as gt,z as _t,zt as vt}from"./artifact-C0wQlV2Q.js";import W from"node:process";import*as yt from"os";import*as bt from"crypto";import*as G from"fs";import*as xt from"path";import{ok as St}from"assert";import*as Ct from"util";import{TextDecoder as wt}from"node:util";import{Buffer as Tt}from"node:buffer";import*as Et from"node:crypto";import{createHash as Dt}from"node:crypto";import{pathToFileURL as Ot}from"node:url";import*as K from"node:fs/promises";import{access as kt,chmod as At,lstat as jt,mkdir as Mt,mkdtemp as Nt,readdir as Pt,rm as Ft,stat as It,writeFile as Lt}from"node:fs/promises";import*as q from"node:path";import Rt,{dirname as zt,join as Bt,resolve as Vt,sep as Ht}from"node:path";import{constants as Ut}from"node:fs";import{spawn as Wt}from"node:child_process";import*as Gt from"node:os";import Kt,{homedir as qt,tmpdir as Jt}from"node:os";import*as Yt from"stream";const Xt={api_error:`API Error`,configuration:`Configuration Error`,context_overflow:`Context Overflow`,internal:`Internal Error`,llm_fetch_error:`LLM Fetch Error`,llm_timeout:`LLM Timeout`,model_not_found:`Model Not Found`,permission:`Permission Error`,provider_auth_error:`Provider Authentication Error`,quota_exceeded:`Quota Exceeded`,rate_limit:`Rate Limit`,validation:`Validation Error`};function Zt(e){return e.type===`rate_limit`?`:warning:`:e.type===`llm_timeout`?`:hourglass:`:e.type===`llm_fetch_error`||e.retryable?`:warning:`:`:x:`}function Qt(e){let t=Zt(e),n=Xt[e.type],r=[];return r.push(`${t} **${n}**`),r.push(``),r.push(e.message),e.details!=null&&(r.push(``),r.push(`> ${e.details}`)),e.suggestedAction!=null&&(r.push(``),r.push(`**Suggested action:** ${e.suggestedAction}`)),e.retryable&&(r.push(``),r.push(`_This error is retryable._`)),e.resetTime!=null&&(r.push(``),r.push(`_Rate limit resets at: ${e.resetTime.toISOString()}_`)),r.join(` `)}function $t(e,t,n,r){return{type:e,message:t,retryable:n,details:r?.details,suggestedAction:r?.suggestedAction,resetTime:r?.resetTime}}const en=[/fetch failed/i,/connect\s*timeout/i,/connecttimeouterror/i,/timed?\s*out/i,/econnrefused/i,/econnreset/i,/etimedout/i,/network error/i];function tn(e){if(e==null)return!1;let t=``;if(typeof e==`string`)t=e;else if(e instanceof Error)t=e.message,`cause`in e&&typeof e.cause==`string`&&(t+=` ${e.cause}`);else if(typeof e==`object`){let n=e;typeof n.message==`string`&&(t=n.message),typeof n.cause==`string`&&(t+=` ${n.cause}`)}return en.some(e=>e.test(t))}function nn(e,t){return $t(`llm_fetch_error`,`LLM request failed: ${e}`,!0,{details:t==null?void 0:`Model: ${t}`,suggestedAction:`This is a transient network error. The request may succeed on retry, or try a different model.`})}function rn(e,t){return $t(`api_error`,`Provider request failed: ${e}`,!0,{details:t==null?void 0:`Model: ${t}`,suggestedAction:`The provider reported this failure as retryable. The request may succeed on retry.`})}function an(e,t){return $t(`configuration`,`Agent error: ${e}`,!1,{details:t==null?void 0:`Requested agent: ${t}`,suggestedAction:`Verify the agent name is correct and the agent is defined in your OpenCode config or provided by a plugin you configured.`})}const on=/Model not found: ([\w.:@+-]+\/[\w.:@+/-]+?)\.(?=\s|$)(?: Did you mean: ([^\n?]*)\?)?/,sn=/^[\w.:@+/-]{1,128}$/;function cn(e){if(typeof e.message!=`string`)return null;let t=on.exec(e.message),n=t?.[1];if(n==null)return null;let r=(t?.[2]??``).split(`,`).map(e=>e.trim()).filter(e=>sn.test(e)).slice(0,5);return $t(`model_not_found`,`Model not found: ${n}.${r.length>0?` Did you mean: ${r.join(`, `)}?`:``}`,!1,{suggestedAction:`Check that the configured model id is correct. If it is, the OpenCode model catalog may not have loaded: make sure the job can reach models.opencode.ai (egress/firewall) or define the model explicitly in the OpenCode config.`})}function ln(){return $t(`provider_auth_error`,`The model provider rejected authentication for this run.`,!1,{details:`Authentication with the configured model provider is unavailable.`,suggestedAction:`Check the model provider credentials and configuration, then try again.`})}function un(e){if(typeof e==`string`&&!(e.length===0||e.length>128))return e}function dn(e){return e.kind===`retry-status`?un(e.reason)===`auth_unavailable`?ln():null:un(e.name)===`ProviderAuthError`?ln():null}function fn(){return $t(`context_overflow`,`The model context window was exceeded while processing this run.`,!1,{details:`The current session reached the model context limit.`,suggestedAction:`Retry the run with a fresh session or reduce the prompt size.`})}function pn(e){return un(e.name)===`ContextOverflowError`?fn():null}const mn=/* @__PURE__ */ new Set([`insufficient_quota`,`usage_not_included`]),hn=[/exhausted (your|the) credits/i,/top up your available balance/i],gn=/usage limit reached\./i,_n=/enable usage from your available balance/i,vn=/[\n\r\u2028\u2029]/;function yn(e){return e.split(vn).some(e=>{let t=gn.exec(e);return t!==null&&_n.test(e.slice(t.index+t[0].length))})}function bn(e){return yn(e)||hn.some(t=>t.test(e))}function xn(e){if(e.kind===`retry-status`)return e.reason===`account_rate_limit`?Sn({resetTime:e.resetAt}):null;let t=e.status;if(t!==void 0&&Number.isFinite(t)&&t===402)return Sn();let n=e.code;if(n!==void 0&&mn.has(n))return Sn();let r=e.message;return typeof r==`string`&&r.length>0&&bn(r)?Sn():null}function Sn(e){return $t(`quota_exceeded`,`Provider quota exceeded. This run has stopped because the configured model has reached its usage limit.`,!1,{details:e?.provider==null?void 0:`Provider: ${e.provider}`,suggestedAction:`Check the provider account/billing settings, wait for the quota to reset, or switch to a different model or provider.`,resetTime:e?.resetTime})}function J(e,t){if(typeof e==`object`&&e)return Object.getOwnPropertyDescriptor(e,t)?.value}function Y(e,t){if(typeof e!=`object`||!e)return null;let n=Object.getOwnPropertyDescriptor(e,t);return typeof n?.value==`string`?n.value:null}function X(e,t){if(typeof e!=`object`||!e)return null;let n=Object.getOwnPropertyDescriptor(e,t);return typeof n?.value==`number`?n.value:null}function Cn(e,t){if(typeof e!=`object`||!e)return null;let n=Object.getOwnPropertyDescriptor(e,t);return typeof n?.value==`boolean`?n.value:null}function Z(e,t){return typeof e!=`object`||!e?null:Object.getOwnPropertyDescriptor(e,t)?.value??null}const wn=/* @__PURE__ */ new Set([`model_not_found`,`model_not_supported`]),Tn=[/\bauth_unavailable\b/i,/\bno auth available\b/i],En=[/\bmodel_not_found\b/i,/\bmodel (?:is )?not (?:supported|found)\b/i];function Dn(e,t){return e.some(e=>e.test(t))}function On(e){if(e===void 0)return;let t=typeof e==`number`?Number.isFinite(e)?new Date(e):void 0:e;if(!(t===void 0||Number.isNaN(t.getTime())))return t}function kn(){return $t(`model_not_found`,`The configured model is not available from the provider.`,!1,{suggestedAction:`Check that the configured model id is correct and supported by the provider, or choose another.`})}function An(e,t){let n=Mn(t).errorInfo.retryable;return n===e.retryable?e:{...e,retryable:n}}function Q(e,t,n,r,i){return{kind:e,evidence:t,stop:n,errorInfo:r,classificationPath:i}}function jn(e){let t=e.reason;if(t===void 0)return null;let n=dn({kind:`retry-status`,reason:t});if(n!==null)return Q(`auth`,`structured`,!0,n,`structured`);let r=xn({kind:`retry-status`,reason:t,resetAt:On(e.resetAt)});return r===null?wn.has(t)?Q(`model-not-found`,`structured`,!0,kn(),`structured`):null:Q(`quota`,`structured`,!0,r,`structured`)}function Mn(e){let t=e.detail??`Unknown session error`;return tn(t)?{errorInfo:nn(t,e.model),classificationPath:`fallback`}:e.status===429?{errorInfo:$t(`rate_limit`,t,!0),classificationPath:`name`}:e.isRetryable===!0?{errorInfo:rn(t,e.model),classificationPath:`structured`}:e.isRetryable===!1?{errorInfo:an(t),classificationPath:`structured`}:{errorInfo:an(t),classificationPath:e.name!==void 0||e.status!==void 0||e.code!==void 0?`name`:`unclassified`}}function Nn(e){let{name:t,status:n,code:r}=e,i=e.message!==void 0&&e.message.length>0?e.message:void 0,a=dn({kind:`session-error`,name:t});if(a!==null)return Q(`auth`,`structured`,!0,a,`structured`);let o=pn({kind:`session-error`,name:t});if(o!==null)return Q(`context-overflow`,`structured`,!1,o,`structured`);if(t===`MessageAbortedError`){let t=Mn(e);return Q(`aborted`,`structured`,!1,t.errorInfo,t.classificationPath)}let s=xn({kind:`session-error`,status:n,code:r});if(s!==null)return Q(`quota`,`structured`,!0,s,`structured`);if(i!==void 0){let t=xn({kind:`session-error`,message:i});if(t!==null)return Q(`quota`,`text`,!0,t,`structured`);let n=cn({kind:`session-error`,message:i});if(n!==null)return Q(`model-not-found`,`text`,!0,n,`fallback`);let r=i.slice(0,2048);if(Dn(Tn,r))return Q(`auth`,`hint`,!1,An(ln(),e),`fallback`);if(Dn(En,r))return Q(`model-not-found`,`hint`,!1,An(kn(),e),`fallback`)}let c=Mn(e);return Q(`unclassified`,`none`,!1,c.errorInfo,c.classificationPath)}function Pn(e){return e.find(e=>typeof e==`string`&&e.length>0)}function Fn(e){return e.find(e=>typeof e==`number`)}function In(e){return e.find(e=>typeof e==`boolean`)}function Ln(e,t={}){let n=J(e,`data`),r=typeof e==`string`?e:Pn([J(n,`message`),J(e,`message`)]);return{source:`terminal-payload`,name:Pn([J(e,`name`),J(n,`name`)]),status:Fn([J(n,`status`),J(n,`statusCode`),J(e,`status`),J(e,`statusCode`)]),code:Pn([J(n,`code`),J(e,`code`)]),message:r,isRetryable:In([J(n,`isRetryable`),J(e,`isRetryable`)]),detail:t.detail,model:t.model}}function Rn(e){return J(e,`type`)===`retry`?{source:`retry-status`,reason:Pn([J(J(e,`action`),`reason`)]),resetAt:Fn([J(e,`next`)])}:null}function zn(e){return e.source===`retry-status`?jn(e):Nn(e)}function Bn(e){return q.join(e.runnerTemp,`fro-bot-attachments`,`${e.runId}-${e.runAttempt}`)}function Vn(e){return e instanceof Error&&`code`in e}async function Hn(e){try{await K.mkdir(e);return}catch(e){if(!Vn(e)||e.code!==`EEXIST`)throw e}let t=await K.lstat(e);if(t.isSymbolicLink())throw Error(`Refusing to use attachment directory ${e}: a symlink already exists at this path`);if(!t.isDirectory())throw Error(`Refusing to use attachment directory ${e}: a non-directory entry already exists at this path`)}async function Un(e){await Hn(q.dirname(e)),await Hn(e)}function Wn(){let e=/* @__PURE__ */ new Map;function t(t){let n=0;for(let r of e.values())r.state===t&&n++;return n}function n(){return t(`outstanding`)===0&&t(`unknown`)===0}return{adopt:(t,n)=>{e.has(t)!==!0&&e.set(t,{label:n,state:`outstanding`})},settle:t=>{let n=e.get(t);n!==void 0&&n.state!==`settled`&&e.set(t,{label:n.label,state:`settled`})},markUnknown:t=>{let n=e.get(t);n!==void 0&&n.state===`outstanding`&&e.set(t,{label:n.label,state:`unknown`})},release:t=>{e.delete(t)},outstanding:()=>t(`outstanding`),unknown:()=>t(`unknown`),isDrainComplete:()=>n(),isPersistenceSafe:()=>n(),snapshot:()=>Array.from(e.entries()).map(([e,t])=>({sessionId:e,label:t.label,state:t.state})),isTracked:t=>e.has(t)}}function Gn(e){return e.startsWith(`shell:`)}function $(e){return Y(e,`sessionID`)}function Kn(e){let t=Y(e,`type`);return t===`sync`?Y(e,`name`)?.replace(/\.\d+$/,``)??t:t}function qn(e){return Z(e,`properties`)??Z(e,`data`)}function Jn(e){return $(Z(e,`properties`))??$(Z(e,`data`))}const Yn=[`OWNER`,`MEMBER`,`COLLABORATOR`];async function Xn(e){let{ledger:t,adapter:n,parentSessionId:r,logger:i,signal:a}=e,o=()=>t.snapshot().filter(e=>!Gn(e.sessionId));if(o().length===0)return y({liveTrackedSessionIds:/* @__PURE__ */ new Set});let s=a===void 0?[]:[a],[c,l]=await Promise.all([n.children(r,...s),n.liveSessionIds(...s)]);if(c.success===!1||l.success===!1){let e=c.success===!1?c.error:l.error,n=o().filter(e=>e.state===`outstanding`);for(let e of n)t.markUnknown(e.sessionId);return i.warning(`Ledger reconciliation failed; marking outstanding entries unknown rather than settling them`,{source:`reconcileLedgerOnce`,parentSessionId:r,unknownCount:n.length,error:e.message}),H(e)}let u=c.data,d=l.data,f=new Set(u.map(e=>e.id)),p=[],m=[],h=/* @__PURE__ */ new Set;for(let e of o())(e.state===`outstanding`||e.state===`unknown`)&&(f.has(e.sessionId)===!1?(t.markUnknown(e.sessionId),m.push(e.sessionId)):d.has(e.sessionId)===!0?h.add(e.sessionId):(t.settle(e.sessionId),p.push(e.sessionId)));return(p.length>0||m.length>0)&&i.debug(`Ledger reconciliation adjusted ownership`,{source:`reconcileLedgerOnce`,parentSessionId:r,settled:p,downgradedToUnknown:m}),y({liveTrackedSessionIds:h})}function Zn(e){let{intervalMs:t=3e4,runPass:n,...r}=e,i=!1,a=!1,o=setInterval(()=>{i||a||(a=!0,(n===void 0?Xn(r):(async()=>n())()).catch(()=>{}).finally(()=>{a=!1}))},t);return{dispose:()=>{i||(i=!0,clearInterval(o))}}}function Qn(e,t){return{children:async(n,r)=>{try{let i=await e.session.children({path:{id:n},query:{directory:t},...r===void 0?{}:{signal:r}});return i.error!=null||i.data==null?H(m(i.error??`session.children returned no data`)):Array.isArray(i.data)?y(i.data.map(e=>({id:e.id}))):H(/* @__PURE__ */ Error(`session.children returned a non-array payload`))}catch(e){return H(m(e))}},liveSessionIds:async n=>{try{let r=await e.session.status({query:{directory:t},...n===void 0?{}:{signal:n}});return r.error!=null||r.data==null?H(m(r.error??`session.status returned no data`)):y(new Set(Object.keys(r.data)))}catch(e){return H(m(e))}}}}function $n(e){return Array.isArray(e)?e.some(e=>{if(Y(e,`type`)!==`tool`||Cn(Z(e,`metadata`),`providerExecuted`)===!0)return!1;let t=Z(e,`state`),n=Cn(Z(t,`metadata`),`interrupted`);return Y(t,`status`)!==`error`||n!==!0}):!1}function er(e,t){switch(e){case`discussion_comment`:case`issue_comment`:case`issues`:case`pull_request`:case`pull_request_review_comment`:case`unsupported`:return null;case`schedule`:case`workflow_dispatch`:switch(t){case`working-dir`:return`working-dir`;case`branch-pr`:return`branch-pr`;case`auto`:return`working-dir`;default:return t}default:return e}}async function tr(e,t,n,r=async(e,t)=>K.writeFile(e,t,`utf8`)){let i=[];for(let a of e){let e=q.join(t,a.filename);try{await r(e,a.content),i.push({type:`file`,mime:`text/plain`,url:Ot(e).toString(),filename:a.filename})}catch(t){n.warning(`Failed to materialize reference file`,{error:x(t),filename:a.filename,path:e})}}return i}function nr(e){switch(e){case`pull_request`:case`issue_comment`:case`issues`:return`affected`;case`workflow_dispatch`:case`schedule`:return`autonomous`;default:return`deferred-or-unknown`}}function rr(e){throw Error(`Unexpected value: ${String(e)}`)}function ir(e){switch(e){case`affected`:return`withhold`;case`autonomous`:case`deferred-or-unknown`:return`provision`;default:return rr(e)}}function ar(e){switch(e){case`affected`:return`file-convention`;case`autonomous`:case`deferred-or-unknown`:return`model-gh`;default:return rr(e)}}function or(e,t){let n=nr(e),r=ir(n);return t===`none`?{delivery:`none`,credential:r}:{delivery:ar(n),credential:r}}function sr(e){let t=Rt.resolve(Rt.normalize(e));return t.endsWith(Rt.sep)&&t.length>1?t.slice(0,-1):t}async function cr(e,t,n){let r=await e.project.list({query:{directory:t}});if(r.error!=null||r.data==null)return n.warning(`SDK project list failed`,{error:x(r.error)}),[];if(!Array.isArray(r.data))return n.warning(`SDK project list returned a non-array payload`,{type:typeof r.data}),[];let i=0,a=[];for(let e of r.data){if(!me(e)){i+=1;continue}let t=dt(e.id),n=dt(e.worktree);t==null||n==null?i+=1:a.push({id:t,worktree:n})}return n.debug(`Discovered projects via SDK`,{total:r.data.length,skipped:i,retained:a.length}),a}async function lr(e,t,n){let r=sr(t),i=await cr(e,t,n);for(let e of i)if(sr(e.worktree)===r)return e;return null}function ur(e,t){return{key:`${e}-${t}`,entityType:e,entityId:t}}function dr(e){return Dt(`sha256`).update(e).digest(`hex`).slice(0,8)}function fr(e,t){return t==null?e:`${e}-${t}`}function pr(e,t){if(e.eventType===`unsupported`)return null;if(e.eventType===`schedule`){let n=typeof e.raw==`object`&&e.raw!=null&&`event`in e.raw?e.raw.event:void 0,r=typeof n==`object`&&n&&`type`in n&&n.type===`schedule`&&`schedule`in n&&typeof n.schedule==`string`?n.schedule:void 0;return ur(`schedule`,fr(`${dr((r!=null&&r.trim().length>0?r:e.action)??`default`)}-${e.runId}`,t))}return e.eventType===`workflow_dispatch`?ur(`dispatch`,fr(String(e.runId),t)):e.target==null?null:e.eventType===`issue_comment`?e.target.kind===`issue`?ur(`issue`,String(e.target.number)):e.target.kind===`pr`?ur(`pr`,String(e.target.number)):null:e.eventType===`discussion_comment`?e.target.kind===`discussion`?ur(`discussion`,String(e.target.number)):null:e.eventType===`issues`?e.target.kind===`issue`?ur(`issue`,String(e.target.number)):null:(e.eventType===`pull_request`||e.eventType===`pull_request_review_comment`)&&e.target.kind===`pr`?ur(`pr`,String(e.target.number)):null}function mr(e){return`fro-bot: ${e.key}`}function hr(e,t){let n=e.filter(e=>e.title===t);return n.length===0?null:n.reduce((e,t)=>t.time.updated>e.time.updated?t:e)}function gr(e){let t=q.resolve(e);return t.endsWith(q.sep)&&t.length>1?t.slice(0,-1):t}async function _r(e,t,n,r){try{let i=await Ae(e,t,r),a=mr(n),o=gr(t),s=hr(i.filter(e=>gr(e.directory)===o).filter(e=>e.time.archived==null&&e.time.compacting==null),a);if(s==null){let e=hr(i.filter(e=>e.time.archived==null&&e.time.compacting==null),a);return e!=null&&r.warning(`Session continuity: matching session has different workspace directory, ignoring`,{sessionId:e.id,sessionDirectory:e.directory,workspacePath:t}),{status:`not-found`}}return{status:`found`,session:s}}catch(e){return{status:`error`,error:x(e)}}}const vr={maxSessions:50,maxAgeDays:30};async function yr(e,t,n,r){let{maxSessions:i,maxAgeDays:a}=n;if(r.info(`Starting session pruning`,{workspacePath:t,maxSessions:i,maxAgeDays:a}),await lr(e,t,r)==null)return r.debug(`No project found for pruning`,{workspacePath:t}),{prunedCount:0,prunedSessionIds:[],remainingCount:0,freedBytes:0};let o=await Ae(e,t,r),s=o.filter(e=>e.parentID==null);if(s.length===0)return{prunedCount:0,prunedSessionIds:[],remainingCount:0,freedBytes:0};let c=[...s].sort((e,t)=>t.time.updated-e.time.updated),l=/* @__PURE__ */ new Date;l.setDate(l.getDate()-a);let u=l.getTime(),d=/* @__PURE__ */ new Set;for(let e of c)e.time.updated>=u&&d.add(e.id);for(let e=0;e!d.has(e.id)),p=/* @__PURE__ */ new Set;for(let e of f){p.add(e.id);for(let t of o)t.parentID===e.id&&p.add(t.id)}if(p.size===0)return r.info(`No sessions to prune`),{prunedCount:0,prunedSessionIds:[],remainingCount:s.length,freedBytes:0};let m=[];for(let t of p)try{await Ue(e,t,r),m.push(t),r.debug(`Pruned session`,{sessionId:t})}catch(e){r.warning(`Failed to prune session`,{sessionId:t,error:x(e)})}let h=s.length-f.length;return r.info(`Session pruning complete`,{prunedCount:m.length,remainingCount:h}),{prunedCount:m.length,prunedSessionIds:m,remainingCount:h,freedBytes:0}}async function br(e,t,n,r,i){if(n!=null&&i?.isExpired()!==!0&&i?.remainingMs()!==0)try{let a,o=i==null?null:new Promise((e,t)=>{a=()=>t(/* @__PURE__ */ Error(`Session title re-assertion aborted`)),i.signal.addEventListener(`abort`,a,{once:!0})});try{let a=e.session.update({path:{id:t},body:{title:n},...i==null?{}:{signal:i.signal}}),s=await Promise.race([a,...o==null?[]:[o]]);if(i?.isExpired()===!0)return;s.error!=null&&r.warning(`Best-effort session title re-assertion failed`,{sessionId:t,sessionTitle:n,error:se(s.error)})}finally{i!=null&&a!=null&&i.signal.removeEventListener(`abort`,a)}}catch(e){if(i?.isExpired()===!0)return;r.warning(`Best-effort session title re-assertion failed`,{sessionId:t,sessionTitle:n,error:x(e)})}}function xr(e){let t=[`--- Fro Bot Run Summary ---`,`Event: ${e.eventType}`,`Repo: ${e.repo}`,`Ref: ${e.ref}`,`Run ID: ${e.runId}`,`Cache: ${e.cacheStatus}`,`Duration: ${e.duration}s`];return e.sessionIds.length>0&&t.push(`Sessions used: ${e.sessionIds.join(`, `)}`),e.logicalKey!=null&&t.push(`Logical Thread: ${e.logicalKey}`),e.createdPRs.length>0&&t.push(`PRs created: ${e.createdPRs.join(`, `)}`),e.createdCommits.length>0&&t.push(`Commits: ${e.createdCommits.join(`, `)}`),e.tokenUsage!=null&&t.push(`Tokens: ${e.tokenUsage.input} in / ${e.tokenUsage.output} out`),t.join(` `)}async function Sr(e,t,n,r){let i=xr(t);try{let t=await n.session.prompt({path:{id:e},body:{noReply:!0,parts:[{type:`text`,text:i}]}});if(t.error!=null){r.warning(`SDK prompt writeback failed`,{sessionId:e,error:se(t.error)});return}r.info(`Session summary written via SDK`,{sessionId:e})}catch(t){r.warning(`SDK prompt writeback failed`,{sessionId:e,error:x(t)})}}const Cr=//;function wr(e){let t=Cr.exec(e),n=t?.[1],r=t?.[2];return n===void 0||r!==`completed`&&r!==`error`?null:{childSessionId:n,state:r}}function Tr(e){if(Y(e,`type`)!==`text`||Cn(e,`synthetic`)!==!0)return null;let t=Y(e,`text`);return t===null?null:wr(t)}const Er=`agent: working`,Dr=/^\d{12}$/;function Or(e){let t=e.value?.trim();return t!=null&&t.length>0?t:void 0}function kr(e,t){return H(Ve(`${e}: ${t}`))}function Ar(e){let[t,...n]=e,r=n.pop();return r===void 0?t.source:`${[t,...n].map(e=>e.source).join(`, `)} or ${r.source}`}function jr(e){let t=Or(e);return t===void 0?y(void 0):t===`aws:kms`||t===`AES256`?y(t):kr(e.source,`must be either 'aws:kms' or 'AES256'`)}function Mr(e,n){let r=jr(e.sseEncryption);if(r.success===!1)return r;let i=r.data,a=Or(e.bucket),o=e.region.map(Or).find(e=>e!==void 0),s=Or(e.endpoint),c=Or(e.expectedBucketOwner),l=Or(e.sseKmsKeyId),u=Or(e.prefix)??`fro-bot-state`;if(e.enabled){if(a===void 0)return H(Ve(`${e.bucket.source} is required`));if(o===void 0&&n.region===`required`)return H(Ve(`${Ar(e.region)} is required`));if(s!==void 0){let t=it(s,e.allowInsecureEndpoint);if(t.success===!1)return kr(e.endpoint.source,t.error.message)}let t=xe(u);if(t.success===!1)return kr(e.prefix.source,t.error.message);if(u=t.data,c!==void 0&&Dr.test(c)===!1)return kr(e.expectedBucketOwner.source,`must be a 12-digit AWS account ID`)}let d={enabled:e.enabled,bucket:a??``,region:o??``,prefix:u,allowInsecureEndpoint:e.allowInsecureEndpoint,...s===void 0?{}:{endpoint:s},...c===void 0?{}:{expectedBucketOwner:c},...i===void 0?{}:{sseEncryption:i},...l===void 0?{}:{sseKmsKeyId:l}};return e.enabled&&l!==void 0&&t(d)!==`aws:kms`?kr(e.sseKmsKeyId.source,`requires the server-side encryption mode to be aws:kms; set ${e.sseEncryption.source} to aws:kms`):y(d)}const Nr={todowrite:[`Todo`,`\x1B[33m\x1B[1m`],todoread:[`Todo`,`\x1B[33m\x1B[1m`],bash:[`Bash`,`\x1B[31m\x1B[1m`],edit:[`Edit`,`\x1B[32m\x1B[1m`],glob:[`Glob`,`\x1B[34m\x1B[1m`],grep:[`Grep`,`\x1B[34m\x1B[1m`],list:[`List`,`\x1B[34m\x1B[1m`],read:[`Read`,`\x1B[35m\x1B[1m`],write:[`Write`,`\x1B[32m\x1B[1m`],websearch:[`Search`,`\x1B[2m\x1B[1m`]},Pr=`\x1B[0m`;function Fr(){return W.env.NO_COLOR==null}function Ir(e,t){let[n,r]=Nr[e.toLowerCase()]??[e,`\x1B[36m\x1B[1m`],i=n.padEnd(10,` `);Fr()?W.stdout.write(`\n${r}|${Pr} ${i} ${Pr}${t}\n`):W.stdout.write(`\n| ${i} ${t}\n`)}function Lr(e){W.stdout.write(`\n${e}\n`)}function Rr(e){let[t,n]=e.split(`/`);if(t==null||n==null||t.length===0||n.length===0)throw Error(`Invalid repository string: ${e}`);return{owner:t,repo:n}}async function zr(e,t,n,r,i){try{let{owner:a,repo:o}=Rr(t),{data:s}=await e.rest.reactions.createForIssueComment({owner:a,repo:o,comment_id:n,content:r});return i.debug(`Created comment reaction`,{commentId:n,content:r,reactionId:s.id}),{id:s.id}}catch(e){return i.warning(`Failed to create comment reaction`,{commentId:n,content:r,error:x(e)}),null}}async function Br(e,t,n,r){try{let{owner:r,repo:i}=Rr(t),{data:a}=await e.rest.reactions.listForIssueComment({owner:r,repo:i,comment_id:n,per_page:100});return a.map(e=>({id:e.id,content:e.content,userLogin:e.user?.login??null}))}catch(e){return r.warning(`Failed to list comment reactions`,{commentId:n,error:x(e)}),[]}}async function Vr(e,t,n,r,i){try{let{owner:a,repo:o}=Rr(t);return await e.rest.reactions.deleteForIssueComment({owner:a,repo:o,comment_id:n,reaction_id:r}),i.debug(`Deleted comment reaction`,{commentId:n,reactionId:r}),!0}catch(e){return i.warning(`Failed to delete comment reaction`,{commentId:n,reactionId:r,error:x(e)}),!1}}async function Hr(e,t,n,r,i,a){let{owner:o,repo:s}=Rr(t);try{return await e.rest.issues.createLabel({owner:o,repo:s,name:n,color:r,description:i}),a.debug(`Created label`,{name:n,color:r}),!0}catch(e){return e instanceof Error&&`status`in e&&e.status===422?(a.debug(`Label already exists`,{name:n}),!0):(a.warning(`Failed to create label`,{name:n,error:x(e)}),!1)}}async function Ur(e,t,n,r,i){try{let{owner:a,repo:o}=Rr(t);return await e.rest.issues.addLabels({owner:a,repo:o,issue_number:n,labels:[...r]}),i.debug(`Added labels to issue`,{issueNumber:n,labels:r}),!0}catch(e){return i.warning(`Failed to add labels to issue`,{issueNumber:n,labels:r,error:x(e)}),!1}}function Wr(e){return e==null?{}:{request:{signal:e}}}async function Gr(e,t,n,r,i,a){try{let{owner:o,repo:s}=Rr(t);return await e.rest.issues.removeLabel({owner:o,repo:s,issue_number:n,name:r,...Wr(a)}),i.debug(`Removed label from issue`,{issueNumber:n,label:r}),`removed`}catch(e){return e instanceof Error&&`status`in e&&e.status===404?(i.debug(`Label was not present on issue`,{issueNumber:n,label:r}),`absent`):(i.warning(`Failed to remove label from issue`,{issueNumber:n,label:r,error:x(e)}),`failed`)}}async function Kr(e,t,n,r,i,a){return await Gr(e,t,n,r,i,a)!==`failed`}async function qr(e,t,n,r,i){try{let{owner:r,repo:a}=Rr(t),{data:o}=await e.rest.issues.listLabelsOnIssue({owner:r,repo:a,issue_number:n,per_page:100,...Wr(i)});return o.map(e=>e.name)}catch(e){return r.warning(`Failed to list labels on issue`,{issueNumber:n,error:x(e)}),null}}function Jr(e){if(typeof e!=`string`)return null;for(let t of e.split(`,`)){if(t.includes(`rel="last"`)===!1)continue;let e=/[?&]page=(\d+)/.exec(t);if(e?.[1]!=null)return Number(e[1])}return null}async function Yr(e,t,n,r,i,a){try{let{owner:i,repo:o}=Rr(t),s=async t=>e.rest.issues.listEvents({owner:i,repo:o,issue_number:n,per_page:100,page:t,...Wr(a)}),c=new Map(r.map(e=>[e.toLowerCase(),e])),l=/* @__PURE__ */ new Map,u=await s(1),d=Jr(u.headers.link)??1,f=d,p=d===1?u:await s(d);for(let e=0;e<3;e++){let t=/* @__PURE__ */ new Map;for(let e of p.data){let n=e.event===`labeled`?c.get(e.label?.name.toLowerCase()??``):void 0;if(n==null)continue;let r=Date.parse(e.created_at);Number.isNaN(r)||r>(t.get(n)??-1/0)&&t.set(n,r)}for(let[e,n]of t)l.has(e)===!1&&l.set(e,n);if(l.size===c.size||f<=1||e+1>=3)break;if(a?.aborted===!0)return null;--f,p=f===1?u:await s(f)}return l}catch(e){return i.warning(`Failed to read issue events`,{issueNumber:n,labels:r,error:x(e)}),null}}async function Xr(e,t,n){try{let{owner:n,repo:r}=Rr(t),{data:i}=await e.rest.repos.get({owner:n,repo:r});return i.default_branch}catch(e){return n.warning(`Failed to get default branch`,{repo:t,error:x(e)}),`main`}}const Zr={admin:`OWNER`,maintain:`MEMBER`,write:`COLLABORATOR`,triage:`COLLABORATOR`};async function Qr(e,t,n,r,i){try{let{data:a}=await e.rest.repos.getCollaboratorPermissionLevel({owner:t,repo:n,username:r}),o=Zr[a.permission]??null;return i.debug(`Resolved sender permission`,{username:r,permission:a.permission,association:o}),o}catch(e){return i.warning(`Failed to resolve sender permission`,{username:r,error:x(e)}),null}}async function $r(e,t,n){try{let{data:n}=await e.rest.users.getByUsername({username:t});return{id:n.id,login:n.login}}catch(e){return n.debug(`Failed to get user by username`,{username:t,error:x(e)}),null}}const ei={maxComments:50,maxCommits:100,maxFiles:100,maxReviews:100,maxBodyBytes:10240,maxTotalBytes:102400},ti=`…[truncated]`;function ni(e,t){if(e.length===0)return{text:``,truncated:!1};let n=new TextEncoder,r=n.encode(e);if(r.length<=t)return{text:e,truncated:!1};let i=t-n.encode(ti).length;if(i<=0)return{text:ti,truncated:!0};let a=r.slice(0,i),o=new TextDecoder(`utf-8`,{fatal:!1}).decode(a);for(;o.length>0&&o.charCodeAt(o.length-1)===65533;)a=a.slice(0,-1),o=new TextDecoder(`utf-8`,{fatal:!1}).decode(a);return{text:o+ti,truncated:!0}}async function ri(e,t,n){let r=[];for(let t=1;t<=50;t++){let n=await e(t);if(r.push(...n),n.length<100)return r}return n.warning(`REST collection pagination limit reached`,{collection:t,maxPages:50}),r}async function ii(e,t,n,r,i,a){try{let[o,s]=await Promise.all([e.rest.issues.get({owner:t,repo:n,issue_number:r}),ri(async i=>(await e.rest.issues.listComments({owner:t,repo:n,issue_number:r,per_page:100,page:i})).data,`issue comments`,a)]),c=o.data,l=ni(c.body??``,i.maxBodyBytes),u=s.slice(Math.max(0,s.length-i.maxComments)).map(e=>({id:e.node_id??String(e.id),author:e.user?.login??null,body:e.body??``,createdAt:e.created_at,authorAssociation:e.author_association,isMinimized:!1})),d=(c.labels??[]).filter(e=>typeof e==`object`&&!!e&&`name`in e).map(e=>({name:e.name??``,color:e.color})),f=(c.assignees??[]).map(e=>({login:e?.login??``}));return{type:`issue`,number:c.number,title:c.title,body:l.text,bodyTruncated:l.truncated,state:c.state,author:c.user?.login??null,createdAt:c.created_at,labels:d,assignees:f,comments:u,commentsTruncated:s.length>u.length,totalComments:s.length}}catch(e){return a.warning(`REST issue fallback failed`,{owner:t,repo:n,number:r,error:x(e)}),null}}async function ai(e,t,n,r,i,a){try{let o=await e.rest.pulls.get({owner:t,repo:n,pull_number:r}),[s,c,l,u]=await Promise.all([ri(async i=>(await e.rest.pulls.listCommits({owner:t,repo:n,pull_number:r,per_page:100,page:i})).data,`pull request commits`,a),e.rest.pulls.listFiles({owner:t,repo:n,pull_number:r,per_page:i.maxFiles+1}),ri(async i=>(await e.rest.pulls.listReviews({owner:t,repo:n,pull_number:r,per_page:100,page:i})).data,`pull request reviews`,a),ri(async i=>(await e.rest.issues.listComments({owner:t,repo:n,issue_number:r,per_page:100,page:i})).data,`pull request comments`,a)]),d=await e.rest.pulls.listRequestedReviewers({owner:t,repo:n,pull_number:r}).catch(e=>(a.warning(`Failed to fetch requested reviewers, defaulting to empty`,{owner:t,repo:n,number:r,error:x(e)}),{data:{users:[],teams:[]}})),f=o.data,p=ni(f.body??``,i.maxBodyBytes),m=f.base.repo?.owner.login,h=f.head.repo?.owner.login,g=h==null||m!==h,_=u.slice(Math.max(0,u.length-i.maxComments)).map(e=>({id:e.node_id??String(e.id),author:e.user?.login??null,body:e.body??``,createdAt:e.created_at,authorAssociation:e.author_association,isMinimized:!1})),v=s.slice(Math.max(0,s.length-i.maxCommits)).map(e=>({oid:e.sha,message:e.commit.message,author:e.commit.author?.name??null})),y=c.data.slice(0,i.maxFiles).map(e=>({path:e.filename,additions:e.additions,deletions:e.deletions,status:e.status})),b=l.slice(Math.max(0,l.length-i.maxReviews)).map(e=>({author:e.user?.login??null,state:e.state,body:e.body??``,createdAt:e.submitted_at??``,comments:[]})),S=(f.labels??[]).map(e=>({name:e.name??``,color:e.color})),C=(f.assignees??[]).map(e=>({login:e?.login??``})),w=(d.data.users??[]).map(e=>e.login),T=(d.data.teams??[]).map(e=>e.name);return{type:`pull_request`,number:f.number,title:f.title,body:p.text,bodyTruncated:p.truncated,state:f.state,author:f.user?.login??null,createdAt:f.created_at,baseBranch:f.base.ref,headBranch:f.head.ref,isFork:g,labels:S,assignees:C,comments:_,commentsTruncated:u.length>_.length,totalComments:u.length,commits:v,commitsTruncated:s.length>v.length,totalCommits:s.length,files:y,filesTruncated:c.data.length>y.length,totalFiles:c.data.length,reviews:b,reviewsTruncated:l.length>b.length,totalReviews:l.length,authorAssociation:f.author_association,requestedReviewers:w,requestedReviewerTeams:T}}catch(e){return a.warning(`REST pull request fallback failed`,{owner:t,repo:n,number:r,error:x(e)}),null}}async function oi(e,t,n,r,i,a){try{return await e.graphql(` query GetIssue($owner: String!, $repo: String!, $number: Int!, $maxComments: Int!) { diff --git a/dist/post.js b/dist/post.js index a51a3c0974..0de381a4ca 100644 --- a/dist/post.js +++ b/dist/post.js @@ -1 +1 @@ -import{$t as e,G as t,H as n,J as r,K as i,Kt as a,Q as o,R as s,U as c,V as l,W as u,Z as d,c as f,et as p,f as m,g as h,h as g,m as _,n as v,q as y,t as b,tt as x,u as S,w as C}from"./artifact-BIg7elxR.js";import*as w from"node:path";function T(t){let n=e(t);return n.length>0?n:void 0}function E(){let e=T(g.S3_ENABLED),t=T(g.S3_BUCKET),n=T(g.S3_PREFIX);if(e==null||t==null||n==null)return;let r=T(g.S3_REGION)??``,i=T(g.S3_ENDPOINT),a=T(g.S3_EXPECTED_BUCKET_OWNER),o=T(g.S3_ALLOW_INSECURE_ENDPOINT),s=T(g.S3_SSE_ENCRYPTION),c=T(g.S3_SSE_KMS_KEY_ID);return{enabled:e===`true`,bucket:t,region:r,prefix:n,endpoint:i,expectedBucketOwner:a,allowInsecureEndpoint:o===`true`,sseEncryption:s===`aws:kms`||s===`AES256`?s:void 0,sseKmsKeyId:c}}async function D(e){try{let t=T(g.LOCK_HOLDER_ID);if(t==null)return;let r=T(g.LOCK_HOLDER_JOB),i=T(g.LOCK_ACQUISITION_TOKEN),a=E();if(a?.enabled!==!0)return;let o=n(),c=await _(async e=>m({storeConfig:a,repo:o,holderId:t,...r===void 0?{}:{holderJob:r},...i===void 0?{}:{acquisitionToken:i},signal:e,logger:s({phase:`post-lock-release`})}),S,`Lock release exceeded ${S}ms`);if(c.success===!1){e.warning(`Post-action lock release failed (non-fatal)`,{error:c.error.message,repo:o,holderId:t});return}e.info(`Post-action lock release`,{outcome:c.data,repo:o,holderId:t})}catch(t){e.warning(`Post-action lock release threw (non-fatal)`,{error:a(t)})}}async function O(e={}){let t=e.logger??s({phase:`post`});try{await k(t)}finally{await D(t)}}async function k(m){let _=e(g.SHOULD_SAVE_CACHE),S=C(e(g.CACHE_SAVED)),T=e(g.SESSION_ID)||null,D=e(g.OPENCODE_VERSION)||null,O=E();if(m.debug(`Post-action state`,{shouldSaveCache:_,cacheSaved:S,sessionId:T,opencodeVersion:D,hasStoreConfig:O!=null}),_!==`true`)m.info(`Skipping post-action: event was not processed`,{shouldSaveCache:_});else{if(S===`durable`||S===`store-only`||S===`skipped`){let e=S===`durable`?`cache saved by main action`:S===`store-only`?`state persisted to the object store by main action`:`main action skipped the save`;m.info(`Skipping post-action: ${e}`,{cacheSaved:S})}else if(S===`declined-for-safety`)m.info(`Skipping post-action: honoring persistence safety decline from main action, not retrying`,{cacheSaved:S}),await h({cachePersisted:!1,storePersisted:!1,outcome:`ownership-declined`},`post-skip-safety`,m);else{let l=String(u());try{let e=f(),n=w.join(t(),`.git`,`opencode`),a={components:e,runId:u(),logger:m,storagePath:r(),authPath:i(),projectIdPath:n,opencodeVersion:D,...O==null?{}:{storeConfig:O},objectStorePublish:`withhold`},o=O?.enabled===!0;o&&m.info(`Post-action withheld the object-store session publish: the main step has released the coordination lease, so only the Actions cache is retried`);let s=await v(a);await h(s,`post-retry`,m,void 0,o?`lease-released`:void 0),s.cachePersisted===!0?m.info(`Post-action cache saved`,{sessionId:T}):s.outcome===`skipped-empty`?m.info(`Post-action: no cache content to save`,{sessionId:T}):m.info(`Post-action cache save did not persist (${s.outcome})`,{sessionId:T,storePersisted:s.storePersisted})}catch(e){m.warning(`Post-action cache save failed (non-fatal)`,{error:a(e)})}if(O?.enabled===!0)try{let t=s({phase:`post-object-store`}),r=o(O,t),i=n(),a=c();e(g.CLEANUP_METADATA_WRITTEN)!==`true`&&await x(r,O,`github`,i,l,{runId:l,timestamp:(/* @__PURE__ */ new Date()).toISOString(),cleanupSkipped:!0,runAttempt:a},t),await p(r,O,`github`,i,l,y(),t)}catch(e){m.warning(`Post-action object store sync failed (non-fatal)`,{error:a(e)})}}if(d()&&e(g.ARTIFACT_UPLOADED)!==`true`)try{let e=s({phase:`post-artifact-upload`});await b({logPath:y(),runId:u(),runAttempt:c(),invocationIdentity:l(),logger:e})}catch(e){m.warning(`Post-action artifact upload failed (non-fatal)`,{error:a(e)})}}}await O();export{}; \ No newline at end of file +import{$t as e,G as t,H as n,J as r,K as i,Kt as a,Q as o,R as s,U as c,V as l,W as u,Z as d,c as f,et as p,f as m,g as h,h as g,m as _,n as v,q as y,t as b,tt as x,u as S,w as C}from"./artifact-C0wQlV2Q.js";import*as w from"node:path";function T(t){let n=e(t);return n.length>0?n:void 0}function E(){let e=T(g.S3_ENABLED),t=T(g.S3_BUCKET),n=T(g.S3_PREFIX);if(e==null||t==null||n==null)return;let r=T(g.S3_REGION)??``,i=T(g.S3_ENDPOINT),a=T(g.S3_EXPECTED_BUCKET_OWNER),o=T(g.S3_ALLOW_INSECURE_ENDPOINT),s=T(g.S3_SSE_ENCRYPTION),c=T(g.S3_SSE_KMS_KEY_ID);return{enabled:e===`true`,bucket:t,region:r,prefix:n,endpoint:i,expectedBucketOwner:a,allowInsecureEndpoint:o===`true`,sseEncryption:s===`aws:kms`||s===`AES256`?s:void 0,sseKmsKeyId:c}}async function D(e){try{let t=T(g.LOCK_HOLDER_ID);if(t==null)return;let r=T(g.LOCK_HOLDER_JOB),i=T(g.LOCK_ACQUISITION_TOKEN),a=E();if(a?.enabled!==!0)return;let o=n(),c=await _(async e=>m({storeConfig:a,repo:o,holderId:t,...r===void 0?{}:{holderJob:r},...i===void 0?{}:{acquisitionToken:i},signal:e,logger:s({phase:`post-lock-release`})}),S,`Lock release exceeded ${S}ms`);if(c.success===!1){e.warning(`Post-action lock release failed (non-fatal)`,{error:c.error.message,repo:o,holderId:t});return}e.info(`Post-action lock release`,{outcome:c.data,repo:o,holderId:t})}catch(t){e.warning(`Post-action lock release threw (non-fatal)`,{error:a(t)})}}async function O(e={}){let t=e.logger??s({phase:`post`});try{await k(t)}finally{await D(t)}}async function k(m){let _=e(g.SHOULD_SAVE_CACHE),S=C(e(g.CACHE_SAVED)),T=e(g.SESSION_ID)||null,D=e(g.OPENCODE_VERSION)||null,O=E();if(m.debug(`Post-action state`,{shouldSaveCache:_,cacheSaved:S,sessionId:T,opencodeVersion:D,hasStoreConfig:O!=null}),_!==`true`)m.info(`Skipping post-action: event was not processed`,{shouldSaveCache:_});else{if(S===`durable`||S===`store-only`||S===`skipped`){let e=S===`durable`?`cache saved by main action`:S===`store-only`?`state persisted to the object store by main action`:`main action skipped the save`;m.info(`Skipping post-action: ${e}`,{cacheSaved:S})}else if(S===`declined-for-safety`)m.info(`Skipping post-action: honoring persistence safety decline from main action, not retrying`,{cacheSaved:S}),await h({cachePersisted:!1,storePersisted:!1,outcome:`ownership-declined`},`post-skip-safety`,m);else{let l=String(u());try{let e=f(),n=w.join(t(),`.git`,`opencode`),a={components:e,runId:u(),logger:m,storagePath:r(),authPath:i(),projectIdPath:n,opencodeVersion:D,...O==null?{}:{storeConfig:O},objectStorePublish:`withhold`},o=O?.enabled===!0;o&&m.info(`Post-action withheld the object-store session publish: the main step has released the coordination lease, so only the Actions cache is retried`);let s=await v(a);await h(s,`post-retry`,m,void 0,o?`lease-released`:void 0),s.cachePersisted===!0?m.info(`Post-action cache saved`,{sessionId:T}):s.outcome===`skipped-empty`?m.info(`Post-action: no cache content to save`,{sessionId:T}):m.info(`Post-action cache save did not persist (${s.outcome})`,{sessionId:T,storePersisted:s.storePersisted})}catch(e){m.warning(`Post-action cache save failed (non-fatal)`,{error:a(e)})}if(O?.enabled===!0)try{let t=s({phase:`post-object-store`}),r=o(O,t),i=n(),a=c();e(g.CLEANUP_METADATA_WRITTEN)!==`true`&&await x(r,O,`github`,i,l,{runId:l,timestamp:(/* @__PURE__ */ new Date()).toISOString(),cleanupSkipped:!0,runAttempt:a},t),await p(r,O,`github`,i,l,y(),t)}catch(e){m.warning(`Post-action object store sync failed (non-fatal)`,{error:a(e)})}}if(d()&&e(g.ARTIFACT_UPLOADED)!==`true`)try{let e=s({phase:`post-artifact-upload`});await b({logPath:y(),runId:u(),runAttempt:c(),invocationIdentity:l(),logger:e})}catch(e){m.warning(`Post-action artifact upload failed (non-fatal)`,{error:a(e)})}}}await O();export{}; \ No newline at end of file diff --git a/packages/runtime/src/shared/constants.ts b/packages/runtime/src/shared/constants.ts index 253325e123..8379218122 100644 --- a/packages/runtime/src/shared/constants.ts +++ b/packages/runtime/src/shared/constants.ts @@ -57,7 +57,7 @@ export const DEFAULT_MODEL = { // releases, checksum-verified, and fail-closed on mismatch — no silent stock fallback. // FALLBACK_VERSION (in opencode.ts) is the plain stock base used when latest-fetch fails. export const DEFAULT_OPENCODE_VERSION = '1.19.4+harness.5bde2635' -export const DEFAULT_SYSTEMATIC_VERSION = '3.27.2' +export const DEFAULT_SYSTEMATIC_VERSION = '3.28.0' // Systematic for OpenCode V2. 3.27.x loads on both V1 and V2, so the V2 path installs DEFAULT_SYSTEMATIC_VERSION too // and there is no separate V2 pin. The plugin id is the `id` of the object the package's default export carries