Skip to content

Commit 0bf6166

Browse files
authored
Merge branch 'main' into feat/agent-bundle-editable-md
2 parents b0f5d6c + 9147279 commit 0bf6166

341 files changed

Lines changed: 30207 additions & 1274 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/code-release.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,16 @@ jobs:
196196
echo "OK: $bin"
197197
done
198198
199+
# The native codex CLI must ship as a sibling of codex-acp, or the
200+
# app-server harness silently falls back to codex-acp in production.
201+
for f in codex rg; do
202+
if [[ ! -f "$RESOURCES/app.asar.unpacked/.vite/build/codex-acp/$f" ]]; then
203+
echo "FAIL: codex-acp/$f missing in bundled binaries"
204+
exit 1
205+
fi
206+
echo "OK: codex-acp/$f"
207+
done
208+
199209
- name: Install Playwright
200210
run: pnpm --filter code exec playwright install
201211

@@ -223,6 +233,21 @@ jobs:
223233
apps/code/out/*-mac.zip \
224234
apps/code/out/*.blockmap
225235
236+
# Hash the same files uploaded above; finalize-release turns these into
237+
# the download tables in the release notes.
238+
- name: Compute artifact checksums
239+
env:
240+
MATRIX_ARCH: ${{ matrix.arch }}
241+
working-directory: apps/code/out
242+
run: shasum -a 256 *.dmg *-mac.zip *.blockmap > "checksums-macos-$MATRIX_ARCH.txt"
243+
244+
- name: Upload checksums artifact
245+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
246+
with:
247+
name: checksums-macos-${{ matrix.arch }}
248+
path: apps/code/out/checksums-macos-${{ matrix.arch }}.txt
249+
retention-days: 1
250+
226251
- name: Upload mac manifest artifact
227252
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
228253
with:
@@ -332,6 +357,20 @@ jobs:
332357
$files = $items | Select-Object -ExpandProperty FullName
333358
gh release upload "v$env:APP_VERSION" --repo PostHog/code --clobber @files
334359
360+
# Hash the same files uploaded above (minus latest.yml); finalize-release
361+
# turns these into the download tables in the release notes.
362+
- name: Compute artifact checksums
363+
shell: bash
364+
working-directory: apps/code/out
365+
run: sha256sum *.exe *.blockmap > checksums-windows-x64.txt
366+
367+
- name: Upload checksums artifact
368+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
369+
with:
370+
name: checksums-windows-x64
371+
path: apps/code/out/checksums-windows-x64.txt
372+
retention-days: 1
373+
335374
publish-linux:
336375
needs: [prepare-release]
337376
strategy:
@@ -444,6 +483,21 @@ jobs:
444483
apps/code/out/*.deb \
445484
apps/code/out/*.rpm
446485
486+
# Hash the same files uploaded above; finalize-release turns these into
487+
# the download tables in the release notes.
488+
- name: Compute artifact checksums
489+
env:
490+
MATRIX_ARCH: ${{ matrix.arch }}
491+
working-directory: apps/code/out
492+
run: sha256sum *.AppImage *.deb *.rpm > "checksums-linux-$MATRIX_ARCH.txt"
493+
494+
- name: Upload checksums artifact
495+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
496+
with:
497+
name: checksums-linux-${{ matrix.arch }}
498+
path: apps/code/out/checksums-linux-${{ matrix.arch }}.txt
499+
retention-days: 1
500+
447501
finalize-release:
448502
needs: [publish-macos, publish-windows, publish-linux]
449503
# Publish only when every platform built successfully. Without an `if:` override
@@ -471,6 +525,7 @@ jobs:
471525
with:
472526
sparse-checkout: |
473527
apps/code/scripts/merge-mac-manifests.mjs
528+
apps/code/scripts/generate-release-download-tables.mjs
474529
sparse-checkout-cone-mode: false
475530

476531
- name: Setup Node.js
@@ -508,10 +563,19 @@ jobs:
508563
run: |
509564
gh release upload "v$APP_VERSION" --repo PostHog/code --clobber /tmp/latest-mac.yml
510565
566+
- name: Download checksum artifacts
567+
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
568+
with:
569+
pattern: checksums-*
570+
merge-multiple: true
571+
path: /tmp/checksums
572+
511573
- name: Publish GitHub release
512574
env:
513575
GH_TOKEN: ${{ steps.app-token.outputs.token }}
514576
APP_VERSION: ${{ steps.version.outputs.version }}
515577
run: |
516578
gh api repos/PostHog/code/releases/generate-notes -f tag_name="v$APP_VERSION" --jq '.body' > /tmp/release-notes.md
579+
printf '\n' >> /tmp/release-notes.md
580+
node apps/code/scripts/generate-release-download-tables.mjs "$APP_VERSION" /tmp/checksums >> /tmp/release-notes.md
517581
gh release edit "v$APP_VERSION" --repo PostHog/code --draft=false --notes-file /tmp/release-notes.md

.github/workflows/code-tag.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
contains(github.event.pull_request.labels.*.name, 'Create release'))
2727
permissions:
2828
contents: write
29+
actions: write
2930
runs-on: ubuntu-latest
3031
steps:
3132
- name: Get app token
@@ -45,7 +46,7 @@ jobs:
4546
id: quiet
4647
if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && github.event.inputs.quiet_retries != '0')
4748
env:
48-
GH_TOKEN: ${{ steps.app-token.outputs.token }}
49+
GH_TOKEN: ${{ github.token }}
4950
QUIET_RETRIES: ${{ github.event.inputs.quiet_retries || 0 }}
5051
run: |
5152
RETRIES="${QUIET_RETRIES}"

.github/workflows/test.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ jobs:
1515
outputs:
1616
code: ${{ steps.filter.outputs.code }}
1717
workflow: ${{ steps.filter.outputs.workflow }}
18+
packages: ${{ steps.filter.outputs.packages }}
1819
steps:
1920
- name: Detect relevant changes
2021
id: filter
@@ -36,6 +37,8 @@ jobs:
3637
- "!.env.example"
3738
workflow:
3839
- ".github/workflows/test.yml"
40+
packages:
41+
- "packages/**"
3942
4043
unit-test:
4144
needs: changes
@@ -172,3 +175,72 @@ jobs:
172175
name: playwright-report
173176
path: apps/code/playwright-report/
174177
retention-days: 7
178+
179+
e2e:
180+
# Live-model e2e for the @posthog/agent adapters (claude + codex). Runs only
181+
# after the unit + integration jobs pass — a red tree never reaches the
182+
# gateway — and only when a packages/ file changed. Each arm still self-skips
183+
# unless the POSTHOG_CODE_E2E_GATEWAY_PERSONAL_API_KEY secret is present (fork PRs never
184+
# see it) and POSTHOG_CODE_E2E_GATEWAY_URL points at a runner-reachable gateway.
185+
# Drives cheap models (claude-haiku-4-5 / gpt-5-mini), so a run is a handful of
186+
# short turns.
187+
needs: [changes, unit-test, integration-test]
188+
# Always run on any packages/ change (or a change to this workflow), once
189+
# unit-test + integration-test have passed. There is intentionally NO gate on
190+
# the gateway config being present: if the POSTHOG_CODE_E2E_* secret/vars are
191+
# missing, the fail-loud guard (packages/agent/e2e/guard.e2e.test.ts) REDS the
192+
# run rather than skipping to green. Only fork PRs are skipped, since they never
193+
# receive the gateway secret and would red spuriously.
194+
if: ${{ (needs.changes.outputs.packages == 'true' || needs.changes.outputs.workflow == 'true') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) }}
195+
runs-on: ubuntu-latest
196+
timeout-minutes: 30
197+
permissions:
198+
contents: read
199+
steps:
200+
- name: Checkout
201+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
202+
with:
203+
persist-credentials: false
204+
205+
- name: Setup pnpm
206+
uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4.3.0
207+
208+
- name: Setup Node.js
209+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
210+
with:
211+
node-version: 22
212+
cache: "pnpm"
213+
214+
- name: Install dependencies
215+
run: pnpm install --frozen-lockfile
216+
217+
- name: Build agent dependencies
218+
run: |
219+
pnpm --filter @posthog/shared run build
220+
pnpm --filter @posthog/git run build
221+
pnpm --filter @posthog/enricher run build
222+
223+
- name: Download native codex binary
224+
# Non-fatal at the STEP so a failure surfaces as the fail-loud binary guard
225+
# (guard.e2e.test.ts) with a clear message rather than an opaque download
226+
# error. A missing binary then REDS the run (the guard fails when a token is
227+
# set) instead of letting the codex arm silently skip to green.
228+
run: node apps/code/scripts/download-binaries.mjs || echo "codex binary download failed; the binary guard test will red the run"
229+
230+
- name: Run live e2e (both adapters)
231+
run: pnpm --filter agent run test:e2e
232+
# The suite reads these POSTHOG_CODE_E2E_* names directly
233+
# (packages/agent/e2e/config.ts). The personal API key is an org secret; the
234+
# URL and model/environment overrides are org vars.
235+
env:
236+
POSTHOG_CODE_E2E_GATEWAY_PERSONAL_API_KEY: ${{ secrets.POSTHOG_CODE_E2E_GATEWAY_PERSONAL_API_KEY }}
237+
# Accept the URL from either an org var or an org secret — it has ended
238+
# up in both places, and vars.* can't see secrets.
239+
POSTHOG_CODE_E2E_GATEWAY_URL: ${{ vars.POSTHOG_CODE_E2E_GATEWAY_URL || secrets.POSTHOG_CODE_E2E_GATEWAY_URL }}
240+
POSTHOG_CODE_E2E_CLAUDE_MODEL: ${{ vars.POSTHOG_CODE_E2E_CLAUDE_MODEL }}
241+
POSTHOG_CODE_E2E_CODEX_MODEL: ${{ vars.POSTHOG_CODE_E2E_CODEX_MODEL }}
242+
# Optional: set vars.POSTHOG_CODE_E2E_ENVIRONMENT=cloud to exercise the
243+
# cloud code path (sandbox/permission-profile gating). Unset = local. The
244+
# OS-sandbox enforcement test is macOS-gated, so it doesn't red this linux
245+
# runner.
246+
POSTHOG_CODE_E2E_ENVIRONMENT: ${{ vars.POSTHOG_CODE_E2E_ENVIRONMENT }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ bin/
1616

1717
# tsup bundled config artifacts (temporary files left behind when bundling TS configs)
1818
*.config.bundled_*.mjs
19+
# vite bundled config artifacts (left behind when a vitest run is interrupted)
20+
*.config.ts.timestamp-*.mjs
1921

2022
# Environment
2123
.env

apps/code/scripts/download-binaries.mjs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
existsSync,
88
mkdirSync,
99
realpathSync,
10+
renameSync,
1011
rmSync,
1112
} from "node:fs";
1213
import { dirname, join } from "node:path";
@@ -47,6 +48,40 @@ const BINARIES = [
4748
return target;
4849
},
4950
},
51+
{
52+
name: "codex",
53+
version: "0.140.0",
54+
getUrl: (version, target) => {
55+
if (target.includes("windows")) {
56+
return `https://github.com/openai/codex/releases/download/rust-v${version}/codex-${target}.exe.zip`;
57+
}
58+
return `https://github.com/openai/codex/releases/download/rust-v${version}/codex-${target}.tar.gz`;
59+
},
60+
getTarget: () => {
61+
const { platform, arch } = process;
62+
const targets = {
63+
darwin: { arm64: "aarch64-apple-darwin", x64: "x86_64-apple-darwin" },
64+
linux: {
65+
arm64: "aarch64-unknown-linux-musl",
66+
x64: "x86_64-unknown-linux-musl",
67+
},
68+
win32: {
69+
arm64: "aarch64-pc-windows-msvc",
70+
x64: "x86_64-pc-windows-msvc",
71+
},
72+
};
73+
const platformTargets = targets[platform];
74+
if (!platformTargets)
75+
throw new Error(`Unsupported platform: ${platform}`);
76+
const target = platformTargets[arch];
77+
if (!target) throw new Error(`Unsupported arch: ${arch}`);
78+
return target;
79+
},
80+
// The codex release archive contains a target-suffixed binary
81+
// (e.g. `codex-aarch64-apple-darwin`); rename it to `codex` after extract.
82+
archiveBinaryName: (target) =>
83+
process.platform === "win32" ? `codex-${target}.exe` : `codex-${target}`,
84+
},
5085
{
5186
name: "rg",
5287
version: "15.0.0",
@@ -159,6 +194,13 @@ async function downloadBinary(binary) {
159194
await extractArchive(archivePath, DEST_DIR);
160195
rmSync(archivePath);
161196

197+
if (binary.archiveBinaryName) {
198+
const extractedPath = join(DEST_DIR, binary.archiveBinaryName(target));
199+
if (extractedPath !== binaryPath && existsSync(extractedPath)) {
200+
renameSync(extractedPath, binaryPath);
201+
}
202+
}
203+
162204
if (!existsSync(binaryPath)) {
163205
throw new Error(`Binary not found after extraction: ${binaryPath}`);
164206
}

0 commit comments

Comments
 (0)