fix(pipeline): resolve SafeToAutoRun deadlock and sync freezing (v0.5.20) (#589)
This commit is contained in:
@@ -545,10 +545,13 @@ function setupMonitor() {
|
||||
const toolName = toolCall?.name || stepType.replace('CORTEX_STEP_TYPE_', '').toLowerCase();
|
||||
let command = toolName;
|
||||
|
||||
let isSafeToAutoRun = false;
|
||||
|
||||
// Parse argumentsJson for command details
|
||||
if (toolCall?.argumentsJson) {
|
||||
try {
|
||||
const args = JSON.parse(toolCall.argumentsJson);
|
||||
isSafeToAutoRun = args.SafeToAutoRun === true;
|
||||
if (args.CommandLine) {
|
||||
command = `${toolName}: ${args.CommandLine.substring(0, 1500)}`;
|
||||
} else if (args.TargetFile) {
|
||||
@@ -563,33 +566,38 @@ function setupMonitor() {
|
||||
const description = `Step #${si} (${stepType.replace('CORTEX_STEP_TYPE_', '')})`;
|
||||
ctx.logToFile(`[STEP-PROBE] ★ WAITING! step=${si} type=${stepType} cmd='${command}'`);
|
||||
|
||||
if (si !== ctx.lastPendingStepIndex) {
|
||||
ctx.stallProbed = true; // found WAITING — stop retrying
|
||||
// Track highest step index for auto-resolve
|
||||
if (si > ctx.lastPendingStepIndex) {
|
||||
ctx.lastPendingStepIndex = si;
|
||||
if (si !== ctx.lastPendingStepIndex) {
|
||||
ctx.stallProbed = true; // found WAITING — stop retrying
|
||||
// Track highest step index for auto-resolve
|
||||
if (si > ctx.lastPendingStepIndex) {
|
||||
ctx.lastPendingStepIndex = si;
|
||||
}
|
||||
lastPendingTime = Date.now();
|
||||
ctx.sawRunningAfterPending = false;
|
||||
// Skip pending for workspace-less AG windows (project=default)
|
||||
if (ctx.projectName === 'default') {
|
||||
ctx.logToFile(`[STEP-PROBE] skip pending: ctx.projectName=default (no workspace)`);
|
||||
} else {
|
||||
// Always write pending — Bot decides auto-approve (prevents double-fire)
|
||||
writePendingApproval({
|
||||
conversation_id: ctx.activeSessionId,
|
||||
command,
|
||||
description,
|
||||
step_type: ['view_file', 'list_dir', 'find_by_name', 'read_file', 'grep_search'].includes(toolName) ? 'file_permission'
|
||||
: ['write_to_file', 'replace_file_content', 'multi_replace_file_content'].includes(toolName) ? 'code_edit'
|
||||
: ['browser_subagent', 'open_browser_url'].includes(toolName) ? 'browser_subagent'
|
||||
: toolName,
|
||||
step_index: si,
|
||||
source: 'step_probe',
|
||||
safe_to_auto_run: isSafeToAutoRun,
|
||||
});
|
||||
if (isSafeToAutoRun) {
|
||||
const truncatedCmd = command.length > 500 ? command.substring(0, 500) + '\n...(이하 생략)' : command;
|
||||
ctx.writeChatSnapshot(`⚡ **자동 실행됨** (step ${si})\n\n\`\`\`\n${truncatedCmd}\n\`\`\``);
|
||||
}
|
||||
}
|
||||
}
|
||||
lastPendingTime = Date.now();
|
||||
ctx.sawRunningAfterPending = false;
|
||||
// Skip pending for workspace-less AG windows (project=default)
|
||||
if (ctx.projectName === 'default') {
|
||||
ctx.logToFile(`[STEP-PROBE] skip pending: ctx.projectName=default (no workspace)`);
|
||||
} else {
|
||||
// Always write pending — Bot decides auto-approve (prevents double-fire)
|
||||
writePendingApproval({
|
||||
conversation_id: ctx.activeSessionId,
|
||||
command,
|
||||
description,
|
||||
step_type: ['view_file', 'list_dir', 'find_by_name', 'read_file', 'grep_search'].includes(toolName) ? 'file_permission'
|
||||
: ['write_to_file', 'replace_file_content', 'multi_replace_file_content'].includes(toolName) ? 'code_edit'
|
||||
: ['browser_subagent', 'open_browser_url'].includes(toolName) ? 'browser_subagent'
|
||||
: toolName,
|
||||
step_index: si,
|
||||
source: 'step_probe',
|
||||
});
|
||||
}
|
||||
}
|
||||
// NOTE: no break — process ALL parallel WAITING steps
|
||||
// NOTE: no break — process ALL parallel WAITING steps
|
||||
}
|
||||
}
|
||||
if (!foundWaiting) {
|
||||
@@ -626,9 +634,11 @@ function setupMonitor() {
|
||||
const toolCall = oStep?.metadata?.toolCall;
|
||||
const toolName = toolCall?.name || (oStep.type || '').replace('CORTEX_STEP_TYPE_', '').toLowerCase();
|
||||
let command = toolName;
|
||||
let isSafeToAutoRun = false;
|
||||
if (toolCall?.argumentsJson) {
|
||||
try {
|
||||
const args = JSON.parse(toolCall.argumentsJson);
|
||||
isSafeToAutoRun = args.SafeToAutoRun === true;
|
||||
if (args.CommandLine) command = `${toolName}: ${args.CommandLine.substring(0, 1500)}`;
|
||||
else if (args.TargetFile) command = `${toolName}: ${args.TargetFile}`;
|
||||
else {
|
||||
@@ -655,7 +665,12 @@ function setupMonitor() {
|
||||
: toolName,
|
||||
step_index: actualIndex,
|
||||
source: 'step_probe_utf8_offset',
|
||||
safe_to_auto_run: isSafeToAutoRun,
|
||||
});
|
||||
if (isSafeToAutoRun) {
|
||||
const truncatedCmd = command.length > 500 ? command.substring(0, 500) + '\n...(이하 생략)' : command;
|
||||
ctx.writeChatSnapshot(`⚡ **자동 실행됨** (step ${actualIndex})\n\n\`\`\`\n${truncatedCmd}\n\`\`\``);
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE: no break — process ALL parallel WAITING steps
|
||||
@@ -1024,7 +1039,7 @@ function setupMonitor() {
|
||||
|
||||
|
||||
/** Write a pending approval file matching Bot's ApprovalRequest dataclass. */
|
||||
export function writePendingApproval(data: { conversation_id: string; command: string; description: string; step_type?: string; step_index?: number; source?: string; buttons?: Array<{ text: string; index: number }>; modified_files?: string[]; edit_step_indices?: number[] }) {
|
||||
export function writePendingApproval(data: { conversation_id: string; command: string; description: string; step_type?: string; step_index?: number; source?: string; buttons?: Array<{ text: string; index: number }>; modified_files?: string[]; edit_step_indices?: number[]; safe_to_auto_run?: boolean }) {
|
||||
try {
|
||||
const pendingDir = path.join(ctx.bridgePath, 'pending');
|
||||
if (!fs.existsSync(pendingDir)) { fs.mkdirSync(pendingDir, { recursive: true }); }
|
||||
@@ -1063,6 +1078,7 @@ export function writePendingApproval(data: { conversation_id: string; command: s
|
||||
existing.description = data.description;
|
||||
if (data.step_type) existing.step_type = data.step_type;
|
||||
if (data.step_index !== undefined) existing.step_index = data.step_index;
|
||||
if (data.safe_to_auto_run !== undefined) existing.safe_to_auto_run = data.safe_to_auto_run;
|
||||
existing.source = 'dom_observer+step_probe'; // mark as merged
|
||||
fs.promises.writeFile(efPath, JSON.stringify(existing, null, 2), 'utf-8').catch(e => {
|
||||
ctx.logToFile(`[DEDUP] merge write error: ${e.message}`);
|
||||
|
||||
Reference in New Issue
Block a user