mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
SYM-93: add scriptable Codex PR preflight runner (#1245)
Co-authored-by: Steven Enamakel <31011319+senamakel@users.noreply.github.com> Co-authored-by: WOZCODE <contact@withwoz.com> Co-authored-by: sanil-23 <sanil@vezures.xyz> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Cyrus Gray <144336577+graycyrus@users.noreply.github.com> Co-authored-by: CodeGhost21 <164498022+CodeGhost21@users.noreply.github.com> Co-authored-by: oxoxDev <164490987+oxoxDev@users.noreply.github.com> Co-authored-by: Mega Mind <146339422+M3gA-Mind@users.noreply.github.com> Co-authored-by: Gaurang Patel <ptelgm.yt@gmail.com> Co-authored-by: unn-Known1 <unn-known1@users.noreply.github.com> Co-authored-by: Steven Enamakel <enamakel@tinyhumans.ai> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Steven Enamakel <senamakel@users.noreply.github.com> Co-authored-by: Steven Enamakel's Droid <enamakel.agent@tinyhumans.ai> Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: senamakel-droid <281415773+senamakel-droid@users.noreply.github.com> Co-authored-by: YellowSnnowmann <167776381+YellowSnnowmann@users.noreply.github.com> Co-authored-by: Neil <neil@maha.xyz> Co-authored-by: Neel Mistry <neelmistry@Neels-MacBook-Pro.local> Co-authored-by: obchain <167975049+obchain@users.noreply.github.com> Co-authored-by: Jwalin Shah <jshah1331@gmail.com>
This commit is contained in:
co-authored by
Steven Enamakel
WOZCODE
sanil-23
Claude Opus 4.7
Cyrus Gray
CodeGhost21
oxoxDev
Mega Mind
Gaurang Patel
unn-Known1
Steven Enamakel
github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Cursor Agent
Steven Enamakel
Steven Enamakel's Droid
google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
senamakel-droid
YellowSnnowmann
Neil
Neel Mistry
obchain
Jwalin Shah
parent
ea74183e4f
commit
932703f5f2
@@ -4,6 +4,14 @@ Use this checklist for Codex web sessions, Linear-launched implementation agents
|
||||
|
||||
## Required Preflight
|
||||
|
||||
Run the scriptable preflight wrapper (recommended):
|
||||
|
||||
```bash
|
||||
node scripts/codex-pr-preflight.mjs --strict-path --lightweight
|
||||
```
|
||||
|
||||
Use `--lightweight` when you only need environment/repo checks plus changed-surface validation recommendations (it skips heavier runtime validations).
|
||||
|
||||
Run this before editing files:
|
||||
|
||||
```bash
|
||||
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { execSync } from 'node:child_process';
|
||||
|
||||
const REQUIRED_FILES = ['AGENTS.md', 'docs/src/README.md', 'Cargo.toml', 'app/package.json'];
|
||||
const APP_PATTERNS = [/^app\//, /^docs\//];
|
||||
const ROOT_RUST_PATTERNS = [/^src\//, /^tests\//, /^Cargo\.toml$/, /^Cargo\.lock$/];
|
||||
const TAURI_PATTERNS = [/^app\/src-tauri\//];
|
||||
|
||||
function hasPattern(files, patterns) {
|
||||
return files.some((file) => patterns.some((pattern) => pattern.test(file)));
|
||||
}
|
||||
|
||||
function runGit(command, repoRoot) {
|
||||
return execSync(command, { cwd: repoRoot, encoding: 'utf8' }).trim();
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
return {
|
||||
lightweight: argv.includes('--lightweight'),
|
||||
strictPath: argv.includes('--strict-path'),
|
||||
expectedPath: process.env.CODEX_EXPECT_REPO_PATH || '/workspace/openhuman',
|
||||
};
|
||||
}
|
||||
|
||||
function runCheck(label, ok, details = '') {
|
||||
return { label, ok, details };
|
||||
}
|
||||
|
||||
function summarize(checks) {
|
||||
const failed = checks.filter((check) => !check.ok);
|
||||
for (const check of checks) {
|
||||
const prefix = check.ok ? 'PASS' : 'FAIL';
|
||||
const details = check.details ? ` :: ${check.details}` : '';
|
||||
console.log(`[${prefix}] ${check.label}${details}`);
|
||||
}
|
||||
return failed.length;
|
||||
}
|
||||
|
||||
function recommendations(changedFiles, lightweight) {
|
||||
const lines = [];
|
||||
if (hasPattern(changedFiles, APP_PATTERNS)) {
|
||||
lines.push('pnpm --filter openhuman-app format:check');
|
||||
lines.push('pnpm typecheck');
|
||||
lines.push('pnpm --dir app exec vitest run <changed-test-files> --config test/vitest.config.ts');
|
||||
}
|
||||
if (hasPattern(changedFiles, ROOT_RUST_PATTERNS)) {
|
||||
lines.push('cargo fmt --manifest-path Cargo.toml --all --check');
|
||||
if (!lightweight) lines.push('pnpm debug rust <test-filter>');
|
||||
}
|
||||
if (hasPattern(changedFiles, TAURI_PATTERNS)) {
|
||||
lines.push('cargo fmt --manifest-path app/src-tauri/Cargo.toml --all --check');
|
||||
}
|
||||
return [...new Set(lines)];
|
||||
}
|
||||
|
||||
function main() {
|
||||
const options = parseArgs(process.argv.slice(2));
|
||||
const repoRoot = process.cwd();
|
||||
const checks = [];
|
||||
|
||||
checks.push(runCheck('working directory exists', fs.existsSync(repoRoot), repoRoot));
|
||||
if (options.strictPath) {
|
||||
checks.push(runCheck('expected repo path', path.resolve(repoRoot) === path.resolve(options.expectedPath), `expected ${options.expectedPath}, got ${repoRoot}`));
|
||||
}
|
||||
|
||||
for (const file of REQUIRED_FILES) {
|
||||
checks.push(runCheck(`required file: ${file}`, fs.existsSync(path.join(repoRoot, file))));
|
||||
}
|
||||
|
||||
let branch = '';
|
||||
let remotes = '';
|
||||
let changed = '';
|
||||
try {
|
||||
branch = runGit('git branch --show-current', repoRoot);
|
||||
checks.push(runCheck('branch naming convention', /^codex\/[A-Z]+-\d+[-a-z0-9]*$/i.test(branch), branch));
|
||||
} catch (error) {
|
||||
checks.push(runCheck('branch readable', false, String(error)));
|
||||
}
|
||||
|
||||
try {
|
||||
remotes = runGit('git remote -v', repoRoot);
|
||||
if (!remotes) {
|
||||
checks.push(runCheck('git remote configured (recommended)', true, 'no remotes configured in this checkout'));
|
||||
} else {
|
||||
const hasExpectedRemote = /(jwalin-shah\/openhuman|tinyhumansai\/openhuman)/.test(remotes);
|
||||
checks.push(runCheck('expected git remote present', hasExpectedRemote));
|
||||
}
|
||||
} catch (error) {
|
||||
checks.push(runCheck('git remote readable', false, String(error)));
|
||||
}
|
||||
|
||||
try {
|
||||
changed = runGit('git diff --name-only --diff-filter=ACMR HEAD', repoRoot);
|
||||
checks.push(runCheck('changed files readable', true, changed || 'no changed files'));
|
||||
} catch (error) {
|
||||
checks.push(runCheck('changed files readable', false, String(error)));
|
||||
}
|
||||
|
||||
const changedFiles = changed ? changed.split('\n').filter(Boolean) : [];
|
||||
const commandRecommendations = recommendations(changedFiles, options.lightweight);
|
||||
|
||||
console.log('\nRecommended validation commands:');
|
||||
if (commandRecommendations.length === 0) {
|
||||
console.log('- (none) no changed files detected');
|
||||
} else {
|
||||
for (const cmd of commandRecommendations) console.log(`- ${cmd}`);
|
||||
}
|
||||
|
||||
const failures = summarize(checks);
|
||||
if (failures > 0) process.exit(1);
|
||||
}
|
||||
|
||||
main();
|
||||
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env node
|
||||
import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { execSync } from 'node:child_process';
|
||||
|
||||
function run(cmd, cwd) {
|
||||
return execSync(cmd, { cwd, stdio: 'pipe', encoding: 'utf8' });
|
||||
}
|
||||
|
||||
function makeRepo(branchName) {
|
||||
const dir = mkdtempSync(path.join(tmpdir(), 'codex-preflight-'));
|
||||
mkdirSync(path.join(dir, 'docs/src'), { recursive: true });
|
||||
mkdirSync(path.join(dir, 'app'), { recursive: true });
|
||||
writeFileSync(path.join(dir, 'AGENTS.md'), '# test\n');
|
||||
writeFileSync(path.join(dir, 'docs/src/README.md'), 'ok\n');
|
||||
writeFileSync(path.join(dir, 'Cargo.toml'), '[package]\nname="x"\nversion="0.1.0"\n');
|
||||
writeFileSync(path.join(dir, 'app/package.json'), '{"name":"x"}\n');
|
||||
run('git init', dir);
|
||||
run('git config user.email test@example.com', dir);
|
||||
run('git config user.name test', dir);
|
||||
run('git add .', dir);
|
||||
run('git commit -m init', dir);
|
||||
run(`git checkout -b ${branchName}`, dir);
|
||||
run('git remote add origin git@github.com:jwalin-shah/openhuman.git', dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
const script = path.resolve('scripts/codex-pr-preflight.mjs');
|
||||
const passRepo = makeRepo('codex/SYM-93-preflight');
|
||||
run(`CODEX_EXPECT_REPO_PATH=${passRepo} node ${script} --strict-path --lightweight`, passRepo);
|
||||
|
||||
const failRepo = makeRepo('feature/not-codex');
|
||||
let failed = false;
|
||||
try {
|
||||
run(`CODEX_EXPECT_REPO_PATH=${failRepo} node ${script} --strict-path --lightweight`, failRepo);
|
||||
} catch {
|
||||
failed = true;
|
||||
}
|
||||
if (!failed) {
|
||||
throw new Error('Expected invalid branch naming to fail preflight');
|
||||
}
|
||||
|
||||
console.log('codex preflight self-test passed');
|
||||
Reference in New Issue
Block a user