mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-25 21:41:12 -07:00
feat(deep-review): allow choice between pre-existing and isolated instances for Gemini and GH CLI
This commit is contained in:
148
.gemini/skills/deep-review/policy.toml
Normal file
148
.gemini/skills/deep-review/policy.toml
Normal file
@@ -0,0 +1,148 @@
|
||||
# --- CORE TOOLS ---
|
||||
[[rule]]
|
||||
toolName = "read_file"
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
|
||||
[[rule]]
|
||||
toolName = "write_file"
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
|
||||
[[rule]]
|
||||
toolName = "grep_search"
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
|
||||
[[rule]]
|
||||
toolName = "glob"
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
|
||||
[[rule]]
|
||||
toolName = "list_directory"
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
|
||||
[[rule]]
|
||||
toolName = "codebase_investigator"
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
|
||||
# --- SHELL COMMANDS ---
|
||||
|
||||
# Git (Safe/Read-only)
|
||||
[[rule]]
|
||||
toolName = "run_shell_command"
|
||||
commandPrefix = [
|
||||
"git blame",
|
||||
"git show",
|
||||
"git grep",
|
||||
"git show-ref",
|
||||
"git ls-tree",
|
||||
"git ls-remote",
|
||||
"git reflog",
|
||||
"git remote -v",
|
||||
"git diff",
|
||||
"git rev-list",
|
||||
"git rev-parse",
|
||||
"git merge-base",
|
||||
"git cherry",
|
||||
"git fetch",
|
||||
"git status",
|
||||
"git st",
|
||||
"git branch",
|
||||
"git br",
|
||||
"git log",
|
||||
"git --version"
|
||||
]
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
|
||||
# GitHub CLI (Read-only)
|
||||
[[rule]]
|
||||
toolName = "run_shell_command"
|
||||
commandPrefix = [
|
||||
"gh workflow list",
|
||||
"gh auth status",
|
||||
"gh checkout view",
|
||||
"gh run view",
|
||||
"gh run job view",
|
||||
"gh run list",
|
||||
"gh run --help",
|
||||
"gh issue view",
|
||||
"gh issue list",
|
||||
"gh label list",
|
||||
"gh pr diff",
|
||||
"gh pr check",
|
||||
"gh pr checks",
|
||||
"gh pr view",
|
||||
"gh pr list",
|
||||
"gh pr status",
|
||||
"gh repo view",
|
||||
"gh job view",
|
||||
"gh api",
|
||||
"gh log"
|
||||
]
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
|
||||
# Node.js/NPM (Generic Tests, Checks, and Build)
|
||||
[[rule]]
|
||||
toolName = "run_shell_command"
|
||||
commandPrefix = [
|
||||
"npm run start",
|
||||
"npm install",
|
||||
"npm run",
|
||||
"npm test",
|
||||
"npm ci",
|
||||
"npm list",
|
||||
"npm --version"
|
||||
]
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
|
||||
# Core Utilities (Safe)
|
||||
[[rule]]
|
||||
toolName = "run_shell_command"
|
||||
commandPrefix = [
|
||||
"sleep",
|
||||
"env",
|
||||
"break",
|
||||
"xargs",
|
||||
"base64",
|
||||
"uniq",
|
||||
"sort",
|
||||
"echo",
|
||||
"which",
|
||||
"ls",
|
||||
"find",
|
||||
"tail",
|
||||
"head",
|
||||
"cat",
|
||||
"cd",
|
||||
"grep",
|
||||
"ps",
|
||||
"pwd",
|
||||
"wc",
|
||||
"file",
|
||||
"stat",
|
||||
"diff",
|
||||
"lsof",
|
||||
"date",
|
||||
"whoami",
|
||||
"uname",
|
||||
"du",
|
||||
"cut",
|
||||
"true",
|
||||
"false",
|
||||
"readlink",
|
||||
"awk",
|
||||
"jq",
|
||||
"rg",
|
||||
"less",
|
||||
"more",
|
||||
"tree"
|
||||
]
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
@@ -12,11 +12,12 @@ import { fileURLToPath } from 'url';
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const prNumber = process.argv[2];
|
||||
const branchName = process.argv[3];
|
||||
const policyPath = process.argv[4];
|
||||
const ISOLATED_CONFIG = process.env.GEMINI_CLI_HOME || path.join(process.env.HOME || '', '.gemini-deep-review');
|
||||
|
||||
async function main() {
|
||||
if (!prNumber || !branchName) {
|
||||
console.error('Usage: tsx entrypoint.ts <PR_NUMBER> <BRANCH_NAME>');
|
||||
if (!prNumber || !branchName || !policyPath) {
|
||||
console.error('Usage: tsx entrypoint.ts <PR_NUMBER> <BRANCH_NAME> <POLICY_PATH>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -27,9 +28,9 @@ async function main() {
|
||||
const tsxBin = path.join(workDir, 'node_modules/.bin/tsx');
|
||||
const geminiBin = path.join(workDir, 'node_modules/.bin/gemini');
|
||||
|
||||
// 1. Run the Parallel Worker
|
||||
// 1. Run the Parallel Reviewer
|
||||
console.log('🚀 Launching Parallel Review Worker...');
|
||||
const workerResult = spawnSync(tsxBin, [path.join(__dirname, 'worker.ts'), prNumber, branchName], {
|
||||
const workerResult = spawnSync(tsxBin, [path.join(__dirname, 'worker.ts'), prNumber, branchName, policyPath], {
|
||||
stdio: 'inherit',
|
||||
env: { ...process.env, GEMINI_CLI_HOME: ISOLATED_CONFIG }
|
||||
});
|
||||
@@ -41,12 +42,7 @@ async function main() {
|
||||
// 2. Launch the Interactive Gemini Session (Local Nightly)
|
||||
console.log('\n✨ Verification complete. Joining interactive session...');
|
||||
|
||||
// Use the mirrored policy if available
|
||||
const policyFile = path.join(ISOLATED_CONFIG, 'policies/policy.toml');
|
||||
const geminiArgs = [];
|
||||
if (fs.existsSync(policyFile)) {
|
||||
geminiArgs.push('--policy', policyFile);
|
||||
}
|
||||
const geminiArgs = ['--policy', policyPath];
|
||||
geminiArgs.push('-p', `Review for PR #${prNumber} is complete. Read the logs in .gemini/logs/review-${prNumber}/ and synthesize your findings.`);
|
||||
|
||||
process.chdir(targetDir);
|
||||
|
||||
@@ -38,7 +38,7 @@ async function main() {
|
||||
config = settings.maintainer.deepReview;
|
||||
}
|
||||
|
||||
const { remoteHost, remoteWorkDir, terminalType, syncAuth } = config;
|
||||
const { remoteHost, remoteWorkDir, terminalType, syncAuth, geminiSetup, ghSetup } = config;
|
||||
|
||||
console.log(`🔍 Fetching metadata for PR #${prNumber}...`);
|
||||
const ghView = spawnSync('gh', ['pr', 'view', prNumber, '--json', 'headRefName', '-q', '.headRefName'], { shell: true });
|
||||
@@ -50,11 +50,17 @@ async function main() {
|
||||
|
||||
const sessionName = `${prNumber}-${branchName.replace(/[^a-zA-Z0-9]/g, '_')}`;
|
||||
|
||||
// 2. Sync Configuration Mirror (Isolated Profile)
|
||||
const ISOLATED_CONFIG = '~/.gemini-deep-review';
|
||||
console.log(`📡 Mirroring environment to ${remoteHost}...`);
|
||||
spawnSync('ssh', [remoteHost, `mkdir -p ${remoteWorkDir}/.gemini/skills/deep-review/scripts/ ${ISOLATED_CONFIG}/policies/`]);
|
||||
// 2. Sync Configuration Mirror (Isolated Profiles)
|
||||
const ISOLATED_GEMINI = geminiSetup === 'isolated' ? '~/.gemini-deep-review' : '~/.gemini';
|
||||
const ISOLATED_GH = ghSetup === 'isolated' ? '~/.gh-deep-review' : '~/.config/gh';
|
||||
const remotePolicyPath = `${ISOLATED_GEMINI}/policies/deep-review-policy.toml`;
|
||||
|
||||
console.log(`📡 Mirroring environment to ${remoteHost}...`);
|
||||
spawnSync('ssh', [remoteHost, `mkdir -p ${remoteWorkDir}/.gemini/skills/deep-review/scripts/ ${ISOLATED_GEMINI}/policies/`]);
|
||||
|
||||
// Sync the policy file specifically
|
||||
spawnSync('rsync', ['-avz', path.join(REPO_ROOT, '.gemini/skills/deep-review/policy.toml'), `${remoteHost}:${remotePolicyPath}`]);
|
||||
|
||||
spawnSync('rsync', ['-avz', '--delete', path.join(REPO_ROOT, '.gemini/skills/deep-review/scripts/'), `${remoteHost}:${remoteWorkDir}/.gemini/skills/deep-review/scripts/`]);
|
||||
|
||||
if (syncAuth) {
|
||||
@@ -63,19 +69,17 @@ async function main() {
|
||||
const syncFiles = ['google_accounts.json', 'settings.json'];
|
||||
for (const f of syncFiles) {
|
||||
const lp = path.join(localGeminiDir, f);
|
||||
if (fs.existsSync(lp)) spawnSync('rsync', ['-avz', lp, `${remoteHost}:${ISOLATED_CONFIG}/${f}`]);
|
||||
if (fs.existsSync(lp)) spawnSync('rsync', ['-avz', lp, `${remoteHost}:${ISOLATED_GEMINI}/${f}`]);
|
||||
}
|
||||
const localPolicies = path.join(localGeminiDir, 'policies/');
|
||||
if (fs.existsSync(localPolicies)) spawnSync('rsync', ['-avz', '--delete', localPolicies, `${remoteHost}:${ISOLATED_CONFIG}/policies/`]);
|
||||
if (fs.existsSync(localPolicies)) spawnSync('rsync', ['-avz', '--delete', localPolicies, `${remoteHost}:${ISOLATED_GEMINI}/policies/`]);
|
||||
const localEnv = path.join(REPO_ROOT, '.env');
|
||||
if (fs.existsSync(localEnv)) spawnSync('rsync', ['-avz', localEnv, `${remoteHost}:${remoteWorkDir}/.env`]);
|
||||
}
|
||||
|
||||
// 3. Construct Clean Command
|
||||
// We use a single entrypoint script to avoid quoting nightmares
|
||||
const envLoader = 'export NVM_DIR="$HOME/.nvm"; [ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"';
|
||||
// Use the locally installed tsx binary
|
||||
const entryCmd = `cd ${remoteWorkDir} && ${envLoader} && export GEMINI_CLI_HOME=${ISOLATED_CONFIG} && ./node_modules/.bin/tsx .gemini/skills/deep-review/scripts/entrypoint.ts ${prNumber} ${branchName}`;
|
||||
const entryCmd = `cd ${remoteWorkDir} && ${envLoader} && export GEMINI_CLI_HOME=${ISOLATED_GEMINI} && export GH_CONFIG_DIR=${ISOLATED_GH} && ./node_modules/.bin/tsx .gemini/skills/deep-review/scripts/entrypoint.ts ${prNumber} ${branchName} ${remotePolicyPath}`;
|
||||
|
||||
const tmuxCmd = `$SHELL -ic ${q(entryCmd)}; exec $SHELL`;
|
||||
const sshInternal = `tmux attach-session -t ${sessionName} 2>/dev/null || tmux new-session -s ${sessionName} -n ${q(branchName)} ${q(tmuxCmd)}`;
|
||||
|
||||
@@ -39,21 +39,32 @@ async function main() {
|
||||
const remoteWorkDir = await prompt('Remote Work Directory', '~/gcli/deepreview');
|
||||
|
||||
console.log(`🔍 Checking state of ${remoteHost}...`);
|
||||
const ghCheck = spawnSync('ssh', [remoteHost, 'command -v gh'], { shell: true });
|
||||
|
||||
// 1. Gemini CLI Isolation Choice
|
||||
const geminiChoice = await prompt('\nGemini CLI Setup: Use [p]re-existing instance or [i]solated sandbox instance? (Isolated is recommended)', 'i');
|
||||
const geminiSetup = geminiChoice.toLowerCase() === 'p' ? 'preexisting' : 'isolated';
|
||||
|
||||
// 2. GitHub CLI Isolation Choice
|
||||
const ghChoice = await prompt('GitHub CLI Setup: Use [p]re-existing instance or [i]solated sandbox instance? (Isolated is recommended)', 'i');
|
||||
const ghSetup = ghChoice.toLowerCase() === 'p' ? 'preexisting' : 'isolated';
|
||||
|
||||
const ISOLATED_GEMINI_CONFIG = '~/.gemini-deep-review';
|
||||
const ISOLATED_GH_CONFIG = '~/.gh-deep-review';
|
||||
|
||||
// System Requirements Check
|
||||
const ghCheck = spawnSync('ssh', [remoteHost, 'sh -lc "command -v gh"'], { stdio: 'pipe' });
|
||||
if (ghCheck.status !== 0) {
|
||||
console.log('\n📥 System Requirements Check:');
|
||||
console.log(' ❌ GitHub CLI (gh) is not installed on remote.');
|
||||
|
||||
const shouldProvision = await confirm('\nWould you like Gemini to automatically provision gh?');
|
||||
|
||||
if (shouldProvision) {
|
||||
console.log(`🚀 Attempting to install gh on ${remoteHost}...`);
|
||||
const osCheck = spawnSync('ssh', [remoteHost, 'uname -s'], { shell: true });
|
||||
const osCheck = spawnSync('ssh', [remoteHost, 'uname -s'], { stdio: 'pipe' });
|
||||
const os = osCheck.stdout.toString().trim();
|
||||
let installCmd = os === 'Linux' ? 'sudo apt update && sudo apt install -y gh' : (os === 'Darwin' ? 'brew install gh' : '');
|
||||
if (installCmd) {
|
||||
spawnSync('ssh', ['-t', remoteHost, installCmd], { stdio: 'inherit', shell: true });
|
||||
spawnSync('ssh', ['-t', remoteHost, installCmd], { stdio: 'inherit' });
|
||||
}
|
||||
} else {
|
||||
console.log('⚠️ Please ensure gh is installed before running again.');
|
||||
@@ -61,21 +72,55 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure remote work dir exists
|
||||
spawnSync('ssh', [remoteHost, `mkdir -p ${remoteWorkDir}`], { shell: true });
|
||||
// Ensure remote work dir and isolated config dirs exist
|
||||
spawnSync('ssh', [remoteHost, `mkdir -p ${remoteWorkDir} ${ISOLATED_GEMINI_CONFIG}/policies/ ${ISOLATED_GH_CONFIG}`], { stdio: 'pipe' });
|
||||
|
||||
// Identity Synchronization Onboarding
|
||||
console.log('\n🔐 Identity & Authentication:');
|
||||
const homeDir = process.env.HOME || '';
|
||||
const localAuth = path.join(homeDir, '.gemini/google_accounts.json');
|
||||
const localEnv = path.join(REPO_ROOT, '.env');
|
||||
const hasAuth = fs.existsSync(localAuth);
|
||||
const hasEnv = fs.existsSync(localEnv);
|
||||
|
||||
// GH Auth Check
|
||||
const ghAuthCmd = ghSetup === 'isolated' ? `export GH_CONFIG_DIR=${ISOLATED_GH_CONFIG} && gh auth status` : 'gh auth status';
|
||||
const remoteGHAuth = spawnSync('ssh', [remoteHost, `sh -lc "${ghAuthCmd}"`], { stdio: 'pipe' });
|
||||
const isGHAuthRemote = remoteGHAuth.status === 0;
|
||||
|
||||
if (isGHAuthRemote) {
|
||||
console.log(` ✅ GitHub CLI is already authenticated on remote (${ghSetup}).`);
|
||||
} else {
|
||||
console.log(` ❌ GitHub CLI is NOT authenticated on remote (${ghSetup}).`);
|
||||
// If it's isolated but global is authenticated, offer to sync
|
||||
if (ghSetup === 'isolated') {
|
||||
const globalGHAuth = spawnSync('ssh', [remoteHost, 'sh -lc "gh auth status"'], { stdio: 'pipe' });
|
||||
if (globalGHAuth.status === 0) {
|
||||
if (await confirm(' Global GH auth found. Sync it to isolated instance?')) {
|
||||
spawnSync('ssh', [remoteHost, `cp -r ~/.config/gh/* ${ISOLATED_GH_CONFIG}/`]);
|
||||
console.log(' ✅ GH Auth synced.');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isGHAuthRemote) console.log(' You may need to run "gh auth login" on the remote machine later.');
|
||||
}
|
||||
|
||||
// Gemini Auth Check
|
||||
const geminiAuthCheck = geminiSetup === 'isolated'
|
||||
? `[ -f ${ISOLATED_GEMINI_CONFIG}/google_accounts.json ]`
|
||||
: '[ -f ~/.gemini/google_accounts.json ]';
|
||||
const remoteGeminiAuth = spawnSync('ssh', [remoteHost, `sh -lc "${geminiAuthCheck}"`], { stdio: 'pipe' });
|
||||
const isGeminiAuthRemote = remoteGeminiAuth.status === 0;
|
||||
|
||||
let syncAuth = false;
|
||||
if (hasAuth || hasEnv) {
|
||||
console.log(` 🔍 Found local identity files: ${[hasAuth ? 'Google Account' : '', hasEnv ? '.env' : ''].filter(Boolean).join(', ')}`);
|
||||
syncAuth = await confirm(' Would you like Gemini to automatically sync your local identity to the remote workstation for seamless authentication?');
|
||||
if (isGeminiAuthRemote) {
|
||||
console.log(` ✅ Gemini CLI is already authenticated on remote (${geminiSetup}).`);
|
||||
} else {
|
||||
const homeDir = process.env.HOME || '';
|
||||
const localAuth = path.join(homeDir, '.gemini/google_accounts.json');
|
||||
const localEnv = path.join(REPO_ROOT, '.env');
|
||||
const hasAuth = fs.existsSync(localAuth);
|
||||
const hasEnv = fs.existsSync(localEnv);
|
||||
|
||||
if (hasAuth || hasEnv) {
|
||||
console.log(` 🔍 Found local Gemini CLI credentials: ${[hasAuth ? 'Google Account' : '', hasEnv ? '.env' : ''].filter(Boolean).join(', ')}`);
|
||||
syncAuth = await confirm(' Would you like Gemini to automatically sync your local credentials to the remote workstation for seamless authentication?');
|
||||
}
|
||||
}
|
||||
|
||||
const terminalType = await prompt('\nTerminal Automation (iterm2 / terminal / none)', 'iterm2');
|
||||
@@ -84,7 +129,6 @@ async function main() {
|
||||
const envLoader = 'export NVM_DIR="$HOME/.nvm"; [ -s "$NVM_DIR/nvm.sh" ] && \\. "$NVM_DIR/nvm.sh"';
|
||||
|
||||
console.log(`\n📦 Checking isolated dependencies in ${remoteWorkDir}...`);
|
||||
// Use a single string for ssh command to avoid quoting issues with spawnSync shell:true
|
||||
const checkCmd = `ssh ${remoteHost} ${q(`${envLoader} && [ -x ${remoteWorkDir}/node_modules/.bin/tsx ] && [ -x ${remoteWorkDir}/node_modules/.bin/gemini ]`)}`;
|
||||
const depCheck = spawnSync(checkCmd, { shell: true });
|
||||
|
||||
@@ -103,7 +147,7 @@ async function main() {
|
||||
try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch (e) {}
|
||||
}
|
||||
settings.maintainer = settings.maintainer || {};
|
||||
settings.maintainer.deepReview = { remoteHost, remoteWorkDir, terminalType, syncAuth };
|
||||
settings.maintainer.deepReview = { remoteHost, remoteWorkDir, terminalType, syncAuth, geminiSetup, ghSetup };
|
||||
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
||||
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
||||
console.log('\n✅ Onboarding complete! Settings saved to .gemini/settings.json');
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
/**
|
||||
* Universal Deep Review Worker (Remote)
|
||||
*
|
||||
* Handles worktree provisioning and parallel task execution.
|
||||
*/
|
||||
import { spawn, spawnSync } from 'child_process';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const workDir = process.cwd();
|
||||
const prNumber = process.argv[2];
|
||||
const branchName = process.argv[3];
|
||||
const policyPath = process.argv[4];
|
||||
|
||||
async function main() {
|
||||
if (!prNumber || !branchName) {
|
||||
console.error('Usage: tsx worker.ts <PR_NUMBER> <BRANCH_NAME>');
|
||||
if (!prNumber || !branchName || !policyPath) {
|
||||
console.error('Usage: tsx worker.ts <PR_NUMBER> <BRANCH_NAME> <POLICY_PATH>');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const workDir = process.cwd(); // This is remoteWorkDir
|
||||
const targetDir = path.join(workDir, branchName);
|
||||
|
||||
// 1. Provision PR Directory (Fast Blobless Clone)
|
||||
if (!fs.existsSync(targetDir)) {
|
||||
console.log(`🌿 Provisioning PR #${prNumber} into ${branchName}...`);
|
||||
// Blobless clone: downloads history but no file contents until checked out. Extremely fast.
|
||||
const cloneCmd = `git clone --filter=blob:none https://github.com/google-gemini/gemini-cli.git ${targetDir}`;
|
||||
spawnSync(cloneCmd, { stdio: 'inherit', shell: true });
|
||||
|
||||
@@ -35,19 +35,14 @@ async function main() {
|
||||
const logDir = path.join(targetDir, `.gemini/logs/review-${prNumber}`);
|
||||
fs.mkdirSync(logDir, { recursive: true });
|
||||
|
||||
const GEMINI_CMD = path.join(workDir, 'node_modules/.bin/gemini');
|
||||
|
||||
// Use mirrored policy if available
|
||||
const policyFile = path.join(process.env.HOME || '', '.gemini/policies/policy.toml');
|
||||
const policyFlag = fs.existsSync(policyFile) ? `--policy ${policyFile}` : '';
|
||||
const geminiBin = path.join(workDir, 'node_modules/.bin/gemini');
|
||||
|
||||
// 2. Define Parallel Tasks
|
||||
const tasks = [
|
||||
{ id: 'build', name: 'Fast Build', cmd: `cd ${targetDir} && npm ci && npm run build` },
|
||||
{ id: 'ci', name: 'CI Checks', cmd: `gh pr checks ${prNumber}` },
|
||||
// Point the analysis at the PR directory specifically
|
||||
{ id: 'review', name: 'Gemini Analysis', cmd: `${GEMINI_CMD} ${policyFlag} --cwd ${targetDir} -p "/review-frontend ${prNumber}"` },
|
||||
{ id: 'verify', name: 'Behavioral Proof', cmd: `${GEMINI_CMD} ${policyFlag} --cwd ${targetDir} -p "Analyze the code in ${targetDir} and exercise it."`, dep: 'build' }
|
||||
{ id: 'review', name: 'Gemini Analysis', cmd: `${geminiBin} --policy ${policyPath} --cwd ${targetDir} -p "/review-frontend ${prNumber}"` },
|
||||
{ id: 'verify', name: 'Behavioral Proof', cmd: `${geminiBin} --policy ${policyPath} --cwd ${targetDir} -p "Analyze the code in ${targetDir} and exercise it to prove it works."`, dep: 'build' }
|
||||
];
|
||||
|
||||
const state: Record<string, any> = {};
|
||||
@@ -68,7 +63,6 @@ async function main() {
|
||||
proc.on('close', (code) => {
|
||||
const exitCode = code ?? 0;
|
||||
state[task.id].status = exitCode === 0 ? 'SUCCESS' : 'FAILED';
|
||||
// Write exit code for remote polling
|
||||
fs.writeFileSync(path.join(logDir, `${task.id}.exit`), exitCode.toString());
|
||||
render();
|
||||
});
|
||||
@@ -90,8 +84,6 @@ async function main() {
|
||||
const allDone = tasks.every(t => ['SUCCESS', 'FAILED'].includes(state[t.id].status));
|
||||
if (allDone) {
|
||||
console.log(`\n✨ Verification complete. Launching interactive session...`);
|
||||
// cd into the targetDir for the final interactive session
|
||||
process.chdir(targetDir);
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user