Increase CLI timeout to 15min, fix result file reprocessing, and save outlines directly

- Bump Claude Code subprocess timeout from 5 to 15 minutes for longer content tasks
- Fix scheduler result file loop: unlink source if already exists in processed/ dir
- Pass outline save path to execution brain so it writes directly to network share

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fix/customer-field-migration
PeninsulaInd 2026-03-08 14:38:48 -05:00
parent af67ae166d
commit 8f2ec48e10
3 changed files with 46 additions and 9 deletions

View File

@ -218,10 +218,10 @@ class LLMAdapter:
) )
try: try:
stdout, stderr = proc.communicate(input=prompt, timeout=300) stdout, stderr = proc.communicate(input=prompt, timeout=900)
except subprocess.TimeoutExpired: except subprocess.TimeoutExpired:
proc.kill() proc.kill()
return "Error: Claude Code execution timed out after 5 minutes." return "Error: Claude Code execution timed out after 15 minutes."
if proc.returncode != 0: if proc.returncode != 0:
return f"Execution error: {stderr or 'unknown error'}" return f"Execution error: {stderr or 'unknown error'}"

View File

@ -653,6 +653,9 @@ class Scheduler:
result_path.rename(processed_dir / result_path.name) result_path.rename(processed_dir / result_path.name)
except OSError as e: except OSError as e:
log.warning("Could not move result file %s: %s", result_path.name, e) log.warning("Could not move result file %s: %s", result_path.name, e)
# If it already exists in processed/, delete the source to stop reprocessing
if (processed_dir / result_path.name).exists():
result_path.unlink(missing_ok=True)
# ── Folder Watcher ── # ── Folder Watcher ──

View File

@ -228,6 +228,7 @@ def _build_phase1_prompt(
cora_path: str, cora_path: str,
capabilities_default: str, capabilities_default: str,
is_service_page: bool = False, is_service_page: bool = False,
outline_save_path: str = "",
) -> str: ) -> str:
"""Build the Phase 1 prompt that triggers the content-researcher skill. """Build the Phase 1 prompt that triggers the content-researcher skill.
@ -286,10 +287,19 @@ def _build_phase1_prompt(
f'\nWhen asked about company capabilities, respond with: "{capabilities_default}"' f'\nWhen asked about company capabilities, respond with: "{capabilities_default}"'
) )
parts.append( if outline_save_path:
"\nDeliver the outline as a complete markdown document with sections, " parts.append(
"headings, entity targets, and keyword placement notes." f"\nSave the finished outline to `{outline_save_path}`. "
) "Create any missing directories first. "
"The outline must be a complete markdown document with sections, "
"headings, entity targets, and keyword placement notes. "
"Do NOT save it anywhere else."
)
else:
parts.append(
"\nDeliver the outline as a complete markdown document with sections, "
"headings, entity targets, and keyword placement notes."
)
return "\n".join(parts) return "\n".join(parts)
@ -847,12 +857,29 @@ def _run_phase1(
capabilities_default: str, capabilities_default: str,
is_service_page: bool = False, is_service_page: bool = False,
) -> str: ) -> str:
# Compute the outline save path upfront so the execution brain writes
# directly to the network share (or local fallback).
slug = _slugify(keyword) or "unknown"
outline_path = ""
if config.content.outline_dir:
primary = Path(config.content.outline_dir) / slug
try:
primary.mkdir(parents=True, exist_ok=True)
outline_path = str(primary / "outline.md")
except OSError as e:
log.warning("Network path unavailable (%s), falling back to local: %s", primary, e)
if not outline_path:
local = _LOCAL_CONTENT_DIR / slug
local.mkdir(parents=True, exist_ok=True)
outline_path = str(local / "outline.md")
# ClickUp: move to automation underway # ClickUp: move to automation underway
if task_id: if task_id:
_sync_clickup_start(ctx, task_id) _sync_clickup_start(ctx, task_id)
prompt = _build_phase1_prompt( prompt = _build_phase1_prompt(
url, keyword, content_type, cora_path, capabilities_default, is_service_page url, keyword, content_type, cora_path, capabilities_default, is_service_page,
outline_save_path=outline_path,
) )
log.info("Phase 1 — researching + outlining for '%s' (%s)", keyword, url or "new content") log.info("Phase 1 — researching + outlining for '%s' (%s)", keyword, url or "new content")
@ -874,8 +901,15 @@ def _run_phase1(
_sync_clickup_fail(ctx, task_id, result) _sync_clickup_fail(ctx, task_id, result)
return result return result
# Save the outline # Verify the outline was saved by the execution brain
outline_path = _save_content(result, keyword, "outline.md", config) if not Path(outline_path).is_file():
log.warning(
"Execution brain did not save outline to %s; saving result text as fallback.",
outline_path,
)
Path(outline_path).parent.mkdir(parents=True, exist_ok=True)
Path(outline_path).write_text(result, encoding="utf-8")
log.info("Outline saved to: %s", outline_path) log.info("Outline saved to: %s", outline_path)
# ClickUp: move to outline review + store OutlinePath # ClickUp: move to outline review + store OutlinePath