diff --git a/.github/workflows/agents-api.yml b/.github/workflows/api-acceptance.yml similarity index 94% rename from .github/workflows/agents-api.yml rename to .github/workflows/api-acceptance.yml index 9310cee92..2f1ac3f80 100644 --- a/.github/workflows/agents-api.yml +++ b/.github/workflows/api-acceptance.yml @@ -1,4 +1,4 @@ -name: OpenAgentCore checks +name: api-acceptance on: push: @@ -13,7 +13,7 @@ on: - 'Makefile' - 'scripts/build-agents-api.sh' - 'scripts/build-agents-api-image.sh' - - '.github/workflows/agents-api.yml' + - '.github/workflows/api-acceptance.yml' pull_request: paths: - 'services/agents-api/**' @@ -25,7 +25,7 @@ on: - 'Makefile' - 'scripts/build-agents-api.sh' - 'scripts/build-agents-api-image.sh' - - '.github/workflows/agents-api.yml' + - '.github/workflows/api-acceptance.yml' permissions: contents: read @@ -35,7 +35,7 @@ concurrency: cancel-in-progress: true jobs: - sessions: + official-client: runs-on: ubuntu-latest timeout-minutes: 20 services: @@ -58,11 +58,11 @@ jobs: with: go-version-file: go.mod cache: true - - name: Verify dedicated execution persistence + - name: Build standalone commands and verify migration entrypoints env: OAC_TEST_DATABASE_URL: postgres://agents_api:agents_api_test_only@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/oac_ci_tests?sslmode=disable run: | - OAC_DEV_CORE_BUILD_DIR="$RUNNER_TEMP/oac-core-build" make check-agents-api + OAC_DEV_CORE_BUILD_DIR="$RUNNER_TEMP/oac-core-build" make build-agents-api OAC_DATABASE_URL="$OAC_TEST_DATABASE_URL" "$RUNNER_TEMP/oac-core-build/oac-core-migrate" "$RUNNER_TEMP/oac-core-build/oac-core-device" --help "$RUNNER_TEMP/oac-core-build/oac-core-environment-key" --help diff --git a/.github/workflows/native-daemon.yml b/.github/workflows/native-daemon.yml deleted file mode 100644 index f947efae4..000000000 --- a/.github/workflows/native-daemon.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: native-daemon - -on: - pull_request: - workflow_dispatch: - -permissions: - contents: read - -jobs: - native: - strategy: - fail-fast: false - matrix: - os: [ubuntu-22.04, macos-14, windows-2022] - runs-on: ${{ matrix.os }} - timeout-minutes: 30 - defaults: - run: - shell: bash - steps: - - uses: actions/checkout@v7 - - uses: actions/setup-go@v7 - with: - go-version-file: go.mod - - name: Build the native daemon - run: go build -o "$RUNNER_TEMP/oac-daemon${{ runner.os == 'Windows' && '.exe' || '' }}" ./apps/parsar-daemon/cmd/parsar-daemon - - name: Native filesystem, authentication and process lifecycle - run: >- - go test -race -count=1 - ./internal/runtimefs - ./apps/parsar-daemon/internal/auth - ./apps/parsar-daemon/internal/paths - ./apps/parsar-daemon/internal/daemonize - ./apps/parsar-daemon/internal/agent/clirunner - - name: Native Harness ownership and environment identity - run: >- - go test -race -count=1 - ./apps/parsar-daemon/internal/agent/codex - ./apps/parsar-daemon/internal/agent/claudesdk - ./apps/parsar-daemon/internal/agent/mcode - -run 'TestJSONRPCClientOwnsToolDescendants|TestSelfHostedToolEnvironment' - - name: Native capability snapshots, files and installation - run: >- - go test -race -count=1 - ./apps/parsar-daemon/internal/localworkspace - ./apps/parsar-daemon/internal/cli - -run 'TestNative|TestRuntimeInit|TestRuntimePreparationRejects|TestPreparationFreezesLocalContentsAcrossReconnect|TestSnapshotMarker' - - uses: actions/setup-node@v6 - with: - node-version: '22' - - name: Windows npm and npx stdio launchers without network - if: runner.os == 'Windows' - run: >- - go test -race -count=1 -timeout=2m - ./apps/parsar-daemon/internal/localworkspace - ./apps/parsar-daemon/internal/cli - -run 'TestWindowsPackageManager|TestWindowsRuntimeMCP' - - name: Install pinned native Harness dependencies - run: | - npm install --global pnpm@10.30.3 - pnpm install --frozen-lockfile --filter @parsar/claude-sdk-adapter... - pnpm --filter @parsar/claude-sdk-adapter build - npm install --prefix "$RUNNER_TEMP/native-tools" --no-save @openai/codex@0.153.4 - mkdir -p "$RUNNER_TEMP/claude-runtime" - cp packages/claude-sdk-adapter/package.json "$RUNNER_TEMP/claude-runtime/" - cp -R packages/claude-sdk-adapter/dist "$RUNNER_TEMP/claude-runtime/" - npm install --prefix "$RUNNER_TEMP/claude-runtime" --omit=dev --ignore-scripts --package-lock=false - - name: Verify native Harness startup without model requests - run: | - if [[ "$RUNNER_OS" == Windows ]]; then - export CLAUDE_CODE_GIT_BASH_PATH='C:\Program Files\Git\bin\bash.exe' - fi - node scripts/native-harness-smoke.mjs --codex-package "$RUNNER_TEMP/native-tools/node_modules/@openai/codex" --claude-runtime "$RUNNER_TEMP/claude-runtime" - - uses: actions/upload-artifact@v6 - with: - name: oac-daemon-${{ runner.os }}-${{ runner.arch }} - path: ${{ runner.temp }}/oac-daemon* - if-no-files-found: error diff --git a/.github/workflows/native-installer.yml b/.github/workflows/native.yml similarity index 66% rename from .github/workflows/native-installer.yml rename to .github/workflows/native.yml index 44d620945..027caed1c 100644 --- a/.github/workflows/native-installer.yml +++ b/.github/workflows/native.yml @@ -1,14 +1,38 @@ -name: native-installer +name: native-check on: pull_request: + paths: + - 'apps/parsar-daemon/**' + - 'internal/**' + - 'contracts/agents-api/**' + - 'packages/claude-sdk-adapter/**' + - 'packages/mcode-harness/**' + - 'packages/tsconfig/**' + - 'scripts/build-native-installer*' + - 'scripts/native-harness-smoke.mjs' + - 'scripts/build-mcode-harness.sh' + - 'go.mod' + - 'go.sum' + - 'go.work' + - 'go.work.sum' + - 'package.json' + - 'pnpm-lock.yaml' + - 'pnpm-workspace.yaml' + - 'tsconfig.base.json' + - '.npmrc' + - '.github/workflows/native.yml' workflow_dispatch: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - bundle: + platform: strategy: fail-fast: false matrix: @@ -30,6 +54,34 @@ jobs: run: | go build -ldflags "-X github.com/MiniMax-AI-Dev/parsar/apps/parsar-daemon/internal/cli.Version=$GITHUB_SHA" -o "$RUNNER_TEMP/oac-daemon${{ runner.os == 'Windows' && '.exe' || '' }}" ./apps/parsar-daemon/cmd/parsar-daemon node --test scripts/build-native-installer.test.mjs + - name: Native filesystem, authentication and process lifecycle + run: >- + go test -race -count=1 + ./internal/runtimefs + ./apps/parsar-daemon/internal/auth + ./apps/parsar-daemon/internal/paths + ./apps/parsar-daemon/internal/daemonize + ./apps/parsar-daemon/internal/agent/clirunner + - name: Native Harness ownership and environment identity + run: >- + go test -race -count=1 + ./apps/parsar-daemon/internal/agent/codex + ./apps/parsar-daemon/internal/agent/claudesdk + ./apps/parsar-daemon/internal/agent/mcode + -run 'TestJSONRPCClientOwnsToolDescendants|TestSelfHostedToolEnvironment' + - name: Native capability snapshots, files and installation + run: >- + go test -race -count=1 + ./apps/parsar-daemon/internal/localworkspace + ./apps/parsar-daemon/internal/cli + -run 'TestNative|TestRuntimeInit|TestRuntimePreparationRejects|TestPreparationFreezesLocalContentsAcrossReconnect|TestSnapshotMarker' + - name: Windows npm and npx stdio launchers without network + if: runner.os == 'Windows' + run: >- + go test -race -count=1 -timeout=2m + ./apps/parsar-daemon/internal/localworkspace + ./apps/parsar-daemon/internal/cli + -run 'TestWindowsPackageManager|TestWindowsRuntimeMCP' - name: Build pinned native components run: | npm install --global pnpm@10.30.3 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8ccaa8f12..16b6b0733 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -288,6 +288,17 @@ artifacts. The [maintainer guide](docs/maintainers.md#publish-a-version) owns th workflow, cache behavior and failure-cost tradeoff. +CI coverage has three owners: `core-check` runs the complete `make check` gate; +`api-acceptance.yml` adds the pinned official-client, migration-command and container +acceptance without repeating the full service test suite; `native.yml` +builds and tests the daemon, process lifecycle, Harness protocols and installer +bundle together on Linux, macOS and Windows. Native tests use the packaged +Harnesses and share one daemon build per platform. Changes to native sources, +shared dependencies or packaging inputs trigger that matrix; documentation-only +and unrelated Web changes do not. Manual native validation remains available. +Superseded native runs on the same ref are cancelled. Workflow syntax validation +and release qualification remain separate checks. + Run `make check` before completion. The standalone gate includes all daemon/shared Go tests, Core contract/client/service tests, Core Web and TypeScript client checks (including fixture-only Playwright acceptance), a real dedicated PostgreSQL test diff --git a/scripts/name-allowlist.json b/scripts/name-allowlist.json index 8aa6603a1..40e692e8c 100644 --- a/scripts/name-allowlist.json +++ b/scripts/name-allowlist.json @@ -145,7 +145,7 @@ "reason": "Repository helper filenames are retained source entry points; they do not name installed commands." }, { - "path": ".github/workflows/agents-api.yml", + "path": ".github/workflows/api-acceptance.yml", "regex": "\\.github/workflows/agents-api\\.yml", "reason": "The workflow source filename is an internal repository identity; its display name and artifacts use OpenAgentCore." }, diff --git a/scripts/native-harness-smoke.mjs b/scripts/native-harness-smoke.mjs index f86249b7b..23b83e415 100644 --- a/scripts/native-harness-smoke.mjs +++ b/scripts/native-harness-smoke.mjs @@ -9,8 +9,8 @@ import { createInterface } from 'node:readline'; const options = {}; for (let i = 2; i < process.argv.length; i += 2) { const key = process.argv[i]; - if (!['--codex-package', '--codex-binary', '--claude-runtime', '--only'].includes(key) || !process.argv[i + 1]) { - throw new Error('Expected --codex-package PATH, --codex-binary PATH, --claude-runtime PATH or --only codex|claude'); + if (!['--codex-binary', '--claude-runtime', '--only'].includes(key) || !process.argv[i + 1]) { + throw new Error('Expected --codex-binary PATH, --claude-runtime PATH or --only codex|claude'); } options[key] = process.argv[i + 1]; } @@ -20,23 +20,15 @@ const failure = code => Object.assign(new Error(code), { safeCode: code }); const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); async function codexSmoke(root) { - let binary = options['--codex-binary'] ?? 'codex'; - let prefix = []; - if (options['--codex-package']) { - const directory = resolve(options['--codex-package']); - const manifest = JSON.parse(await readFile(join(directory, 'package.json'), 'utf8')); - if (manifest.version !== '0.153.4') throw failure('codex_package_version'); - binary = process.execPath; - prefix = [join(directory, 'bin', 'codex.js')]; - } + const binary = options['--codex-binary'] ?? 'codex'; const home = join(root, 'codex-home'); const workspace = join(root, 'workspace'); await mkdir(home); await mkdir(workspace); const env = { ...process.env, CODEX_HOME: home }; delete env.OPENAI_API_KEY; delete env.CODEX_API_KEY; - const version = spawnSync(binary, [...prefix, '--version'], { env, encoding: 'utf8', timeout: 15000, maxBuffer: limit }); + const version = spawnSync(binary, ['--version'], { env, encoding: 'utf8', timeout: 15000, maxBuffer: limit }); if (version.error || version.status !== 0 || version.stdout.trim() !== 'codex-cli 0.153.4') throw failure('codex_native_version'); - const child = spawn(binary, [...prefix, 'app-server', '--listen', 'stdio://'], { env, cwd: workspace, stdio: ['pipe', 'pipe', 'pipe'] }); + const child = spawn(binary, ['app-server', '--listen', 'stdio://'], { env, cwd: workspace, stdio: ['pipe', 'pipe', 'pipe'] }); const closed = new Promise(resolve => child.once('close', resolve)); let pending; let bytes = 0;