mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-07 03:00:29 +00:00
parent
e818c50933
commit
88684f34e6
5 changed files with 191 additions and 7 deletions
|
|
@ -1,26 +1,31 @@
|
|||
{
|
||||
"timestamp": "2026-03-21T15:49:43.474655Z",
|
||||
"current_node": "preflight_lint",
|
||||
"timestamp": "2026-03-21T15:54:40.225490Z",
|
||||
"current_node": "implement",
|
||||
"completed_nodes": [
|
||||
"start",
|
||||
"toolchain",
|
||||
"preflight_compile",
|
||||
"preflight_lint"
|
||||
"preflight_lint",
|
||||
"implement"
|
||||
],
|
||||
"node_retries": {
|
||||
"preflight_compile": 1,
|
||||
"implement": 1,
|
||||
"toolchain": 1,
|
||||
"preflight_lint": 1,
|
||||
"start": 1
|
||||
},
|
||||
"context_values": {
|
||||
"internal.run_id": "01KM8HA16H7HVBT2P63W2FSWT5",
|
||||
"current.preamble": "Goal: # Fix: Workflow TOML config lost in detach mode\n\n## Context\n\nWhen running `fabro run -d implement-plan`, the `[pull_request]` config from `fabro.toml` / `cli.toml` / `workflow.toml` is silently dropped, so no PR is created despite `enabled = true` at all config levels.\n\n**Root cause chain**:\n1. `create.rs` tries to copy the workflow TOML as `run.toml`, but checks the **raw CLI arg** (`\"implement-plan\"` — no extension) instead of the resolved path. So `run.toml` is never saved.\n2. `RunEngine` always uses cached `graph.fabro` (a DOT file), so `prepare_workflow` returns `run_cfg = None`, losing all TOML-level config.\n3. `pull_request` and `asset_globs` in `RunConfig` only check `run_cfg` without falling back to `run_defaults`.\n\n## Fix 1: Serialize merged `run_cfg` to `run.toml` in create.rs\n\n**File**: `lib/crates/fabro-cli/src/commands/create.rs`\n\nReplace the raw-file-copy block (lines 53-58) with serialization of the already-merged `WorkflowRunConfig`:\n\n- Change `let prep = prepare_workflow(...)` to `let mut prep = ...`\n- Replace the extension check with:\n ```rust\n if let Some(mut cfg) = prep.run_cfg.take() {\n cfg.graph = \"graph.fabro\".to_string();\n let toml_str = toml::to_string_pretty(&cfg)\n .context(\"Failed to serialize run config\")?;\n tokio::fs::write(run_dir.join(\"run.toml\"), toml_str).await?;\n }\n ```\n- Add `use anyhow::Context;` if needed\n\n**Why serialize instead of copy**: The raw TOML's `graph` field (e.g. `\"workflow.fabro\"`) would point to a nonexistent file in the run dir. Serializing lets us rewrite `graph` to `\"graph.fabro\"` (the cached name). The serialized config also has all defaults merged, env vars resolved, and dockerfiles inlined — making the run dir self-contained.\n\n**Why `take()` not `clone()`**: `WorkflowRunConfig` doesn't derive `Clone`, and `prep.run_cfg` is unused after this point in `create.rs`.\n\n## Fix 2: Use `run.toml` in RunEngine path\n\n**File**: `lib/crates/fabro-cli/src/main.rs` (lines 727-733)\n\nReplace the workflow path resolution to use `run.toml`:\n\n```rust\nlet cached_toml = run_dir.join(\"run.toml\");\nlet workflow_path = if cached_toml.exists() {\n cached_toml\n} else {\n run_dir.join(\"graph.fabro\")\n};\n```\n\nWhen `run.toml` exists, `prepare_workflow` → `resolve_workflow` sees `.toml`, calls `load_run_config`, and `resolve_graph_path` resolves `\"graph.fabro\"` relative to the run dir — pointing to the cached graph that already exists there.\n\n## Fix 3: Add `run_defaults` fallbacks (defense-in-depth)\n\n**File**: `lib/crates/fabro-cli/src/commands/run.rs`\n\nEven with Fixes 1+2, bare `.fabro` files passed directly would still hit `run_cfg = None`. Add fallbacks matching the pattern already used elsewhere in the file:\n\n**3a. `pull_request`** (line 1424-1428):\n```rust\npull_request: run_cfg\n .as_ref()\n .and_then(|c| c.pull_request.as_ref())\n .or(run_defaults.pull_request.as_ref())\n .filter(|p| p.enabled)\n .cloned(),\n```\n\n**3b. `asset_globs`** (line 1429-1433):\n```rust\nasset_globs: run_cfg\n .as_ref()\n .and_then(|c| c.assets.as_ref())\n .or(run_defaults.assets.as_ref())\n .map(|a| a.include.clone())\n .unwrap_or_default(),\n```\n\n**3c. `devcontainer`** (line 969-973):\n```rust\nlet devcontainer_config = if run_cfg\n .as_ref()\n .and_then(|c| c.sandbox.as_ref())\n .or(run_defaults.sandbox.as_ref())\n .and_then(|s| s.devcontainer)\n .unwrap_or(false)\n```\n\n**3d. `sandbox.env`** (line 1300-1306):\n```rust\nif let Some(toml_env) = run_cfg\n .as_ref()\n .and_then(|c| c.sandbox.as_ref())\n .or(run_defaults.sandbox.as_ref())\n .and_then(|s| s.env.clone())\n```\n\n## Verification\n\n1. `cargo build --workspace`\n2. `cargo test --workspace`\n3. `cargo clippy --workspace -- -D warnings`\n4. Manual: `fabro run -d implement-plan` with `[pull_request] enabled = true` in `fabro.toml` → verify `run.toml` in run dir has `graph = \"graph.fabro\"` and `[pull_request]` → verify PR created\n\n\n## Completed stages\n- **toolchain**: success\n - Script: `command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1`\n - Stdout:\n ```\n cargo 1.94.0 (85eff7c80 2026-01-15)\n ```\n - Stderr: (empty)\n- **preflight_compile**: success\n - Script: `cargo check -q --workspace 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n",
|
||||
"thread.preflight_lint.current_node": "implement",
|
||||
"internal.retry_count.implement": 1,
|
||||
"last_stage": "implement",
|
||||
"current.preamble": "Goal: # Fix: Workflow TOML config lost in detach mode\n\n## Context\n\nWhen running `fabro run -d implement-plan`, the `[pull_request]` config from `fabro.toml` / `cli.toml` / `workflow.toml` is silently dropped, so no PR is created despite `enabled = true` at all config levels.\n\n**Root cause chain**:\n1. `create.rs` tries to copy the workflow TOML as `run.toml`, but checks the **raw CLI arg** (`\"implement-plan\"` — no extension) instead of the resolved path. So `run.toml` is never saved.\n2. `RunEngine` always uses cached `graph.fabro` (a DOT file), so `prepare_workflow` returns `run_cfg = None`, losing all TOML-level config.\n3. `pull_request` and `asset_globs` in `RunConfig` only check `run_cfg` without falling back to `run_defaults`.\n\n## Fix 1: Serialize merged `run_cfg` to `run.toml` in create.rs\n\n**File**: `lib/crates/fabro-cli/src/commands/create.rs`\n\nReplace the raw-file-copy block (lines 53-58) with serialization of the already-merged `WorkflowRunConfig`:\n\n- Change `let prep = prepare_workflow(...)` to `let mut prep = ...`\n- Replace the extension check with:\n ```rust\n if let Some(mut cfg) = prep.run_cfg.take() {\n cfg.graph = \"graph.fabro\".to_string();\n let toml_str = toml::to_string_pretty(&cfg)\n .context(\"Failed to serialize run config\")?;\n tokio::fs::write(run_dir.join(\"run.toml\"), toml_str).await?;\n }\n ```\n- Add `use anyhow::Context;` if needed\n\n**Why serialize instead of copy**: The raw TOML's `graph` field (e.g. `\"workflow.fabro\"`) would point to a nonexistent file in the run dir. Serializing lets us rewrite `graph` to `\"graph.fabro\"` (the cached name). The serialized config also has all defaults merged, env vars resolved, and dockerfiles inlined — making the run dir self-contained.\n\n**Why `take()` not `clone()`**: `WorkflowRunConfig` doesn't derive `Clone`, and `prep.run_cfg` is unused after this point in `create.rs`.\n\n## Fix 2: Use `run.toml` in RunEngine path\n\n**File**: `lib/crates/fabro-cli/src/main.rs` (lines 727-733)\n\nReplace the workflow path resolution to use `run.toml`:\n\n```rust\nlet cached_toml = run_dir.join(\"run.toml\");\nlet workflow_path = if cached_toml.exists() {\n cached_toml\n} else {\n run_dir.join(\"graph.fabro\")\n};\n```\n\nWhen `run.toml` exists, `prepare_workflow` → `resolve_workflow` sees `.toml`, calls `load_run_config`, and `resolve_graph_path` resolves `\"graph.fabro\"` relative to the run dir — pointing to the cached graph that already exists there.\n\n## Fix 3: Add `run_defaults` fallbacks (defense-in-depth)\n\n**File**: `lib/crates/fabro-cli/src/commands/run.rs`\n\nEven with Fixes 1+2, bare `.fabro` files passed directly would still hit `run_cfg = None`. Add fallbacks matching the pattern already used elsewhere in the file:\n\n**3a. `pull_request`** (line 1424-1428):\n```rust\npull_request: run_cfg\n .as_ref()\n .and_then(|c| c.pull_request.as_ref())\n .or(run_defaults.pull_request.as_ref())\n .filter(|p| p.enabled)\n .cloned(),\n```\n\n**3b. `asset_globs`** (line 1429-1433):\n```rust\nasset_globs: run_cfg\n .as_ref()\n .and_then(|c| c.assets.as_ref())\n .or(run_defaults.assets.as_ref())\n .map(|a| a.include.clone())\n .unwrap_or_default(),\n```\n\n**3c. `devcontainer`** (line 969-973):\n```rust\nlet devcontainer_config = if run_cfg\n .as_ref()\n .and_then(|c| c.sandbox.as_ref())\n .or(run_defaults.sandbox.as_ref())\n .and_then(|s| s.devcontainer)\n .unwrap_or(false)\n```\n\n**3d. `sandbox.env`** (line 1300-1306):\n```rust\nif let Some(toml_env) = run_cfg\n .as_ref()\n .and_then(|c| c.sandbox.as_ref())\n .or(run_defaults.sandbox.as_ref())\n .and_then(|s| s.env.clone())\n```\n\n## Verification\n\n1. `cargo build --workspace`\n2. `cargo test --workspace`\n3. `cargo clippy --workspace -- -D warnings`\n4. Manual: `fabro run -d implement-plan` with `[pull_request] enabled = true` in `fabro.toml` → verify `run.toml` in run dir has `graph = \"graph.fabro\"` and `[pull_request]` → verify PR created\n\n\n## Completed stages\n- **toolchain**: success\n - Script: `command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1`\n - Stdout:\n ```\n cargo 1.94.0 (85eff7c80 2026-01-15)\n ```\n - Stderr: (empty)\n- **preflight_compile**: success\n - Script: `cargo check -q --workspace 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n- **preflight_lint**: success\n - Script: `cargo clippy -q --workspace -- -D warnings 2>&1`\n - Stdout: (empty)\n - Stderr: (empty)\n",
|
||||
"graph.goal": "# Fix: Workflow TOML config lost in detach mode\n\n## Context\n\nWhen running `fabro run -d implement-plan`, the `[pull_request]` config from `fabro.toml` / `cli.toml` / `workflow.toml` is silently dropped, so no PR is created despite `enabled = true` at all config levels.\n\n**Root cause chain**:\n1. `create.rs` tries to copy the workflow TOML as `run.toml`, but checks the **raw CLI arg** (`\"implement-plan\"` — no extension) instead of the resolved path. So `run.toml` is never saved.\n2. `RunEngine` always uses cached `graph.fabro` (a DOT file), so `prepare_workflow` returns `run_cfg = None`, losing all TOML-level config.\n3. `pull_request` and `asset_globs` in `RunConfig` only check `run_cfg` without falling back to `run_defaults`.\n\n## Fix 1: Serialize merged `run_cfg` to `run.toml` in create.rs\n\n**File**: `lib/crates/fabro-cli/src/commands/create.rs`\n\nReplace the raw-file-copy block (lines 53-58) with serialization of the already-merged `WorkflowRunConfig`:\n\n- Change `let prep = prepare_workflow(...)` to `let mut prep = ...`\n- Replace the extension check with:\n ```rust\n if let Some(mut cfg) = prep.run_cfg.take() {\n cfg.graph = \"graph.fabro\".to_string();\n let toml_str = toml::to_string_pretty(&cfg)\n .context(\"Failed to serialize run config\")?;\n tokio::fs::write(run_dir.join(\"run.toml\"), toml_str).await?;\n }\n ```\n- Add `use anyhow::Context;` if needed\n\n**Why serialize instead of copy**: The raw TOML's `graph` field (e.g. `\"workflow.fabro\"`) would point to a nonexistent file in the run dir. Serializing lets us rewrite `graph` to `\"graph.fabro\"` (the cached name). The serialized config also has all defaults merged, env vars resolved, and dockerfiles inlined — making the run dir self-contained.\n\n**Why `take()` not `clone()`**: `WorkflowRunConfig` doesn't derive `Clone`, and `prep.run_cfg` is unused after this point in `create.rs`.\n\n## Fix 2: Use `run.toml` in RunEngine path\n\n**File**: `lib/crates/fabro-cli/src/main.rs` (lines 727-733)\n\nReplace the workflow path resolution to use `run.toml`:\n\n```rust\nlet cached_toml = run_dir.join(\"run.toml\");\nlet workflow_path = if cached_toml.exists() {\n cached_toml\n} else {\n run_dir.join(\"graph.fabro\")\n};\n```\n\nWhen `run.toml` exists, `prepare_workflow` → `resolve_workflow` sees `.toml`, calls `load_run_config`, and `resolve_graph_path` resolves `\"graph.fabro\"` relative to the run dir — pointing to the cached graph that already exists there.\n\n## Fix 3: Add `run_defaults` fallbacks (defense-in-depth)\n\n**File**: `lib/crates/fabro-cli/src/commands/run.rs`\n\nEven with Fixes 1+2, bare `.fabro` files passed directly would still hit `run_cfg = None`. Add fallbacks matching the pattern already used elsewhere in the file:\n\n**3a. `pull_request`** (line 1424-1428):\n```rust\npull_request: run_cfg\n .as_ref()\n .and_then(|c| c.pull_request.as_ref())\n .or(run_defaults.pull_request.as_ref())\n .filter(|p| p.enabled)\n .cloned(),\n```\n\n**3b. `asset_globs`** (line 1429-1433):\n```rust\nasset_globs: run_cfg\n .as_ref()\n .and_then(|c| c.assets.as_ref())\n .or(run_defaults.assets.as_ref())\n .map(|a| a.include.clone())\n .unwrap_or_default(),\n```\n\n**3c. `devcontainer`** (line 969-973):\n```rust\nlet devcontainer_config = if run_cfg\n .as_ref()\n .and_then(|c| c.sandbox.as_ref())\n .or(run_defaults.sandbox.as_ref())\n .and_then(|s| s.devcontainer)\n .unwrap_or(false)\n```\n\n**3d. `sandbox.env`** (line 1300-1306):\n```rust\nif let Some(toml_env) = run_cfg\n .as_ref()\n .and_then(|c| c.sandbox.as_ref())\n .or(run_defaults.sandbox.as_ref())\n .and_then(|s| s.env.clone())\n```\n\n## Verification\n\n1. `cargo build --workspace`\n2. `cargo test --workspace`\n3. `cargo clippy --workspace -- -D warnings`\n4. Manual: `fabro run -d implement-plan` with `[pull_request] enabled = true` in `fabro.toml` → verify `run.toml` in run dir has `graph = \"graph.fabro\"` and `[pull_request]` → verify PR created\n",
|
||||
"graph.rankdir": "LR",
|
||||
"internal.fidelity": "compact",
|
||||
"internal.retry_count.toolchain": 1,
|
||||
"current_node": "preflight_lint",
|
||||
"current_node": "implement",
|
||||
"thread.start.current_node": "toolchain",
|
||||
"failure_signature": "",
|
||||
"outcome": "success",
|
||||
|
|
@ -30,8 +35,10 @@
|
|||
"failure_class": "",
|
||||
"thread.preflight_compile.current_node": "preflight_lint",
|
||||
"internal.retry_count.preflight_lint": 1,
|
||||
"internal.thread_id": "preflight_compile",
|
||||
"internal.thread_id": "preflight_lint",
|
||||
"last_response": "All four changes are in place. Let me summarize what was done:\n\n## Summary of changes\n\n### Fix 1: `lib/crates/fabro-cli/src/commands/create.rs`\n- Added `use anyhow::Context;`\n- Changed `let prep` to `",
|
||||
"internal.retry_count.start": 1,
|
||||
"response.implement": "All four changes are in place. Let me summarize what was done:\n\n## Summary of changes\n\n### Fix 1: `lib/crates/fabro-cli/src/commands/create.rs`\n- Added `use anyhow::Context;`\n- Changed `let prep` to `let mut prep` to allow taking `run_cfg`\n- Replaced the raw-file-copy block (which checked the CLI arg's extension — always failing for bare workflow names like `\"implement-plan\"`) with serialization of the already-merged `WorkflowRunConfig`. The serialized config rewrites `graph` to `\"graph.fabro\"` (the cached name in the run dir), making the run directory self-contained.\n\n### Fix 2: `lib/crates/fabro-cli/src/main.rs` (RunEngine path)\n- Changed the workflow path resolution in the `RunEngine` command to prefer `run.toml` over `graph.fabro`. When `run.toml` exists, `prepare_workflow` → `resolve_workflow` sees `.toml`, calls `load_run_config`, and resolves `\"graph.fabro\"` relative to the run dir — restoring all TOML-level config (pull_request, assets, etc.).\n\n### Fix 3: `lib/crates/fabro-cli/src/commands/run.rs` (defense-in-depth fallbacks)\n- **3a. `pull_request`**: Added `.or(run_defaults.pull_request.as_ref())` fallback\n- **3b. `asset_globs`**: Added `.or(run_defaults.assets.as_ref())` fallback\n- **3c. `devcontainer`**: Added `.or(run_defaults.sandbox.as_ref())` fallback\n- **3d. `sandbox.env`**: Added `.or(run_defaults.sandbox.as_ref())` fallback\n\nAll changes compile cleanly, pass all `fabro-cli` tests, and pass clippy with `-D warnings`.",
|
||||
"command.stderr": "",
|
||||
"command.output": "",
|
||||
"graph.model_stylesheet": "\n * { model: claude-opus-4-6; }\n "
|
||||
|
|
@ -60,6 +67,30 @@
|
|||
"notes": "Script completed: command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1",
|
||||
"duration_ms": 97
|
||||
},
|
||||
"implement": {
|
||||
"status": "success",
|
||||
"context_updates": {
|
||||
"last_response": "All four changes are in place. Let me summarize what was done:\n\n## Summary of changes\n\n### Fix 1: `lib/crates/fabro-cli/src/commands/create.rs`\n- Added `use anyhow::Context;`\n- Changed `let prep` to `",
|
||||
"response.implement": "All four changes are in place. Let me summarize what was done:\n\n## Summary of changes\n\n### Fix 1: `lib/crates/fabro-cli/src/commands/create.rs`\n- Added `use anyhow::Context;`\n- Changed `let prep` to `let mut prep` to allow taking `run_cfg`\n- Replaced the raw-file-copy block (which checked the CLI arg's extension — always failing for bare workflow names like `\"implement-plan\"`) with serialization of the already-merged `WorkflowRunConfig`. The serialized config rewrites `graph` to `\"graph.fabro\"` (the cached name in the run dir), making the run directory self-contained.\n\n### Fix 2: `lib/crates/fabro-cli/src/main.rs` (RunEngine path)\n- Changed the workflow path resolution in the `RunEngine` command to prefer `run.toml` over `graph.fabro`. When `run.toml` exists, `prepare_workflow` → `resolve_workflow` sees `.toml`, calls `load_run_config`, and resolves `\"graph.fabro\"` relative to the run dir — restoring all TOML-level config (pull_request, assets, etc.).\n\n### Fix 3: `lib/crates/fabro-cli/src/commands/run.rs` (defense-in-depth fallbacks)\n- **3a. `pull_request`**: Added `.or(run_defaults.pull_request.as_ref())` fallback\n- **3b. `asset_globs`**: Added `.or(run_defaults.assets.as_ref())` fallback\n- **3c. `devcontainer`**: Added `.or(run_defaults.sandbox.as_ref())` fallback\n- **3d. `sandbox.env`**: Added `.or(run_defaults.sandbox.as_ref())` fallback\n\nAll changes compile cleanly, pass all `fabro-cli` tests, and pass clippy with `-D warnings`.",
|
||||
"last_stage": "implement"
|
||||
},
|
||||
"notes": "Stage completed: implement",
|
||||
"usage": {
|
||||
"model": "claude-opus-4-6",
|
||||
"input_tokens": 20676,
|
||||
"output_tokens": 5285,
|
||||
"cache_read_tokens": 485060,
|
||||
"cache_write_tokens": 29897,
|
||||
"reasoning_tokens": 28,
|
||||
"cost": 0.706515
|
||||
},
|
||||
"files_touched": [
|
||||
"/home/daytona/workspace/lib/crates/fabro-cli/src/commands/create.rs",
|
||||
"/home/daytona/workspace/lib/crates/fabro-cli/src/commands/run.rs",
|
||||
"/home/daytona/workspace/lib/crates/fabro-cli/src/main.rs"
|
||||
],
|
||||
"duration_ms": 294549
|
||||
},
|
||||
"preflight_lint": {
|
||||
"status": "success",
|
||||
"context_updates": {
|
||||
|
|
@ -70,10 +101,11 @@
|
|||
"duration_ms": 13456
|
||||
}
|
||||
},
|
||||
"next_node_id": "implement",
|
||||
"next_node_id": "simplify_opus",
|
||||
"node_visits": {
|
||||
"start": 1,
|
||||
"preflight_lint": 1,
|
||||
"implement": 1,
|
||||
"toolchain": 1,
|
||||
"preflight_compile": 1
|
||||
}
|
||||
|
|
|
|||
122
nodes/implement/prompt.md
Normal file
122
nodes/implement/prompt.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
Goal: # Fix: Workflow TOML config lost in detach mode
|
||||
|
||||
## Context
|
||||
|
||||
When running `fabro run -d implement-plan`, the `[pull_request]` config from `fabro.toml` / `cli.toml` / `workflow.toml` is silently dropped, so no PR is created despite `enabled = true` at all config levels.
|
||||
|
||||
**Root cause chain**:
|
||||
1. `create.rs` tries to copy the workflow TOML as `run.toml`, but checks the **raw CLI arg** (`"implement-plan"` — no extension) instead of the resolved path. So `run.toml` is never saved.
|
||||
2. `RunEngine` always uses cached `graph.fabro` (a DOT file), so `prepare_workflow` returns `run_cfg = None`, losing all TOML-level config.
|
||||
3. `pull_request` and `asset_globs` in `RunConfig` only check `run_cfg` without falling back to `run_defaults`.
|
||||
|
||||
## Fix 1: Serialize merged `run_cfg` to `run.toml` in create.rs
|
||||
|
||||
**File**: `lib/crates/fabro-cli/src/commands/create.rs`
|
||||
|
||||
Replace the raw-file-copy block (lines 53-58) with serialization of the already-merged `WorkflowRunConfig`:
|
||||
|
||||
- Change `let prep = prepare_workflow(...)` to `let mut prep = ...`
|
||||
- Replace the extension check with:
|
||||
```rust
|
||||
if let Some(mut cfg) = prep.run_cfg.take() {
|
||||
cfg.graph = "graph.fabro".to_string();
|
||||
let toml_str = toml::to_string_pretty(&cfg)
|
||||
.context("Failed to serialize run config")?;
|
||||
tokio::fs::write(run_dir.join("run.toml"), toml_str).await?;
|
||||
}
|
||||
```
|
||||
- Add `use anyhow::Context;` if needed
|
||||
|
||||
**Why serialize instead of copy**: The raw TOML's `graph` field (e.g. `"workflow.fabro"`) would point to a nonexistent file in the run dir. Serializing lets us rewrite `graph` to `"graph.fabro"` (the cached name). The serialized config also has all defaults merged, env vars resolved, and dockerfiles inlined — making the run dir self-contained.
|
||||
|
||||
**Why `take()` not `clone()`**: `WorkflowRunConfig` doesn't derive `Clone`, and `prep.run_cfg` is unused after this point in `create.rs`.
|
||||
|
||||
## Fix 2: Use `run.toml` in RunEngine path
|
||||
|
||||
**File**: `lib/crates/fabro-cli/src/main.rs` (lines 727-733)
|
||||
|
||||
Replace the workflow path resolution to use `run.toml`:
|
||||
|
||||
```rust
|
||||
let cached_toml = run_dir.join("run.toml");
|
||||
let workflow_path = if cached_toml.exists() {
|
||||
cached_toml
|
||||
} else {
|
||||
run_dir.join("graph.fabro")
|
||||
};
|
||||
```
|
||||
|
||||
When `run.toml` exists, `prepare_workflow` → `resolve_workflow` sees `.toml`, calls `load_run_config`, and `resolve_graph_path` resolves `"graph.fabro"` relative to the run dir — pointing to the cached graph that already exists there.
|
||||
|
||||
## Fix 3: Add `run_defaults` fallbacks (defense-in-depth)
|
||||
|
||||
**File**: `lib/crates/fabro-cli/src/commands/run.rs`
|
||||
|
||||
Even with Fixes 1+2, bare `.fabro` files passed directly would still hit `run_cfg = None`. Add fallbacks matching the pattern already used elsewhere in the file:
|
||||
|
||||
**3a. `pull_request`** (line 1424-1428):
|
||||
```rust
|
||||
pull_request: run_cfg
|
||||
.as_ref()
|
||||
.and_then(|c| c.pull_request.as_ref())
|
||||
.or(run_defaults.pull_request.as_ref())
|
||||
.filter(|p| p.enabled)
|
||||
.cloned(),
|
||||
```
|
||||
|
||||
**3b. `asset_globs`** (line 1429-1433):
|
||||
```rust
|
||||
asset_globs: run_cfg
|
||||
.as_ref()
|
||||
.and_then(|c| c.assets.as_ref())
|
||||
.or(run_defaults.assets.as_ref())
|
||||
.map(|a| a.include.clone())
|
||||
.unwrap_or_default(),
|
||||
```
|
||||
|
||||
**3c. `devcontainer`** (line 969-973):
|
||||
```rust
|
||||
let devcontainer_config = if run_cfg
|
||||
.as_ref()
|
||||
.and_then(|c| c.sandbox.as_ref())
|
||||
.or(run_defaults.sandbox.as_ref())
|
||||
.and_then(|s| s.devcontainer)
|
||||
.unwrap_or(false)
|
||||
```
|
||||
|
||||
**3d. `sandbox.env`** (line 1300-1306):
|
||||
```rust
|
||||
if let Some(toml_env) = run_cfg
|
||||
.as_ref()
|
||||
.and_then(|c| c.sandbox.as_ref())
|
||||
.or(run_defaults.sandbox.as_ref())
|
||||
.and_then(|s| s.env.clone())
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
1. `cargo build --workspace`
|
||||
2. `cargo test --workspace`
|
||||
3. `cargo clippy --workspace -- -D warnings`
|
||||
4. Manual: `fabro run -d implement-plan` with `[pull_request] enabled = true` in `fabro.toml` → verify `run.toml` in run dir has `graph = "graph.fabro"` and `[pull_request]` → verify PR created
|
||||
|
||||
|
||||
## Completed stages
|
||||
- **toolchain**: success
|
||||
- Script: `command -v cargo >/dev/null || { curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && sudo ln -sf $HOME/.cargo/bin/* /usr/local/bin/; }; cargo --version 2>&1`
|
||||
- Stdout:
|
||||
```
|
||||
cargo 1.94.0 (85eff7c80 2026-01-15)
|
||||
```
|
||||
- Stderr: (empty)
|
||||
- **preflight_compile**: success
|
||||
- Script: `cargo check -q --workspace 2>&1`
|
||||
- Stdout: (empty)
|
||||
- Stderr: (empty)
|
||||
- **preflight_lint**: success
|
||||
- Script: `cargo clippy -q --workspace -- -D warnings 2>&1`
|
||||
- Stdout: (empty)
|
||||
- Stderr: (empty)
|
||||
|
||||
|
||||
Read the plan file referenced in the goal and implement every step. Make all the code changes described in the plan. Use red/green TDD.
|
||||
5
nodes/implement/provider_used.json
Normal file
5
nodes/implement/provider_used.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"mode": "agent",
|
||||
"provider": "anthropic",
|
||||
"model": "claude-opus-4-6"
|
||||
}
|
||||
19
nodes/implement/response.md
Normal file
19
nodes/implement/response.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
All four changes are in place. Let me summarize what was done:
|
||||
|
||||
## Summary of changes
|
||||
|
||||
### Fix 1: `lib/crates/fabro-cli/src/commands/create.rs`
|
||||
- Added `use anyhow::Context;`
|
||||
- Changed `let prep` to `let mut prep` to allow taking `run_cfg`
|
||||
- Replaced the raw-file-copy block (which checked the CLI arg's extension — always failing for bare workflow names like `"implement-plan"`) with serialization of the already-merged `WorkflowRunConfig`. The serialized config rewrites `graph` to `"graph.fabro"` (the cached name in the run dir), making the run directory self-contained.
|
||||
|
||||
### Fix 2: `lib/crates/fabro-cli/src/main.rs` (RunEngine path)
|
||||
- Changed the workflow path resolution in the `RunEngine` command to prefer `run.toml` over `graph.fabro`. When `run.toml` exists, `prepare_workflow` → `resolve_workflow` sees `.toml`, calls `load_run_config`, and resolves `"graph.fabro"` relative to the run dir — restoring all TOML-level config (pull_request, assets, etc.).
|
||||
|
||||
### Fix 3: `lib/crates/fabro-cli/src/commands/run.rs` (defense-in-depth fallbacks)
|
||||
- **3a. `pull_request`**: Added `.or(run_defaults.pull_request.as_ref())` fallback
|
||||
- **3b. `asset_globs`**: Added `.or(run_defaults.assets.as_ref())` fallback
|
||||
- **3c. `devcontainer`**: Added `.or(run_defaults.sandbox.as_ref())` fallback
|
||||
- **3d. `sandbox.env`**: Added `.or(run_defaults.sandbox.as_ref())` fallback
|
||||
|
||||
All changes compile cleanly, pass all `fabro-cli` tests, and pass clippy with `-D warnings`.
|
||||
6
nodes/implement/status.json
Normal file
6
nodes/implement/status.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"status": "success",
|
||||
"notes": "Stage completed: implement",
|
||||
"failure_reason": null,
|
||||
"timestamp": "2026-03-21T15:54:40.224867+00:00"
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue