feat: reuse executor sessions within Codex tasks
This commit is contained in:
@@ -264,6 +264,36 @@ ${getSafetyConstraints(opts.vcsKind)}`;
|
||||
function buildFixPrompt(opts: ExecutorResumeOpts): string {
|
||||
const { plan, acceptedFindings } = opts;
|
||||
|
||||
if (opts.purpose === "task_plan") {
|
||||
const scopeList = plan.scope.map((s) => ` - ${s}`).join("\n");
|
||||
const criteriaList = plan.acceptanceCriteria.map((c, i) => ` ${i + 1}. ${c}`).join("\n");
|
||||
const cmdsText = plan.verificationCommands.map((cmd) => ` ${cmd.join(" ")}`).join("\n");
|
||||
|
||||
return `# Continued Task Plan: ${plan.title}
|
||||
|
||||
This is a new frozen plan for the same task. Use the repository's current state and your existing task context.
|
||||
|
||||
## Plan
|
||||
|
||||
${plan.planMarkdown}
|
||||
|
||||
## Allowed Scope
|
||||
|
||||
Only modify files within these paths (relative to repository root):
|
||||
${scopeList}
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
${criteriaList}
|
||||
|
||||
## Verification Commands
|
||||
|
||||
After implementation, ensure these commands pass:
|
||||
${cmdsText}
|
||||
|
||||
${getSafetyConstraints(opts.vcsKind)}`;
|
||||
}
|
||||
|
||||
if (acceptedFindings.startsWith("# Scope Remediation")) {
|
||||
return `# Scope Fix Request: ${plan.title}
|
||||
|
||||
@@ -395,6 +425,22 @@ function isSessionInReasonixProject(jsonlPath: string, projectsDir: string, repo
|
||||
return relative !== "" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
||||
}
|
||||
|
||||
export function validateReasonixSessionForRepository(sessionFilePath: string, repoRoot: string): string {
|
||||
const projectsDir = path.join(process.env.HOME || os.homedir(), ".reasonix", "projects");
|
||||
const resolved = path.resolve(sessionFilePath);
|
||||
if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile() || !resolved.endsWith(".jsonl")) {
|
||||
throw new Error(`Reasonix session file not found: ${resolved}`);
|
||||
}
|
||||
if (!fs.existsSync(`${resolved}.meta`)) {
|
||||
throw new Error(`Reasonix session metadata file not found: ${resolved}.meta`);
|
||||
}
|
||||
const workspaceMatches = getWorkspaceFromJsonl(resolved) === repoRoot;
|
||||
if (!workspaceMatches && !isSessionInReasonixProject(resolved, projectsDir, repoRoot)) {
|
||||
throw new Error(`Reasonix session does not belong to repository ${repoRoot}: ${resolved}`);
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
function listJsonlFiles(dir: string, repoRoot?: string): string[] {
|
||||
if (!fs.existsSync(dir)) return [];
|
||||
const result: string[] = [];
|
||||
@@ -638,6 +684,22 @@ export function validateClaudeSessionForWorkflow(
|
||||
repoRoot: string,
|
||||
planTitle: string,
|
||||
): string {
|
||||
const { sessionFile, content } = readClaudeSessionForRepository(sessionId, repoRoot);
|
||||
if (!content.includes(planTitle)) {
|
||||
throw new Error(`Claude session ${sessionId} does not contain frozen plan title: ${planTitle}`);
|
||||
}
|
||||
|
||||
return sessionFile;
|
||||
}
|
||||
|
||||
export function validateClaudeSessionForRepository(sessionId: string, repoRoot: string): string {
|
||||
return readClaudeSessionForRepository(sessionId, repoRoot).sessionFile;
|
||||
}
|
||||
|
||||
function readClaudeSessionForRepository(
|
||||
sessionId: string,
|
||||
repoRoot: string,
|
||||
): { sessionFile: string; content: string } {
|
||||
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId)) {
|
||||
throw new Error(`Invalid Claude session ID: ${sessionId}`);
|
||||
}
|
||||
@@ -688,11 +750,7 @@ export function validateClaudeSessionForWorkflow(
|
||||
if (!sessionMatches || !repoMatches) {
|
||||
throw new Error(`Claude session ${sessionId} does not belong to repository ${repoRoot}`);
|
||||
}
|
||||
if (!content.includes(planTitle)) {
|
||||
throw new Error(`Claude session ${sessionId} does not contain frozen plan title: ${planTitle}`);
|
||||
}
|
||||
|
||||
return sessionFile;
|
||||
return { sessionFile, content };
|
||||
}
|
||||
|
||||
function extractClaudeFailureReason(output: string): string | undefined {
|
||||
|
||||
Reference in New Issue
Block a user