Promote fabro pr, fabro init, fabro diff, fabro preview, fabro graph,
user-level workflows, and GPT-5.4 Mini from accordion items to hero
sections. Reframe lifecycle hooks with positive language.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add March 17 changelog entry (OpenAI Codex backend, fabro docs/discord
commands, gpt-5.4-mini). Update March 16 entry with OAuth error fix.
Add gpt-5.4-mini to model catalog docs and fabro docs/discord to CLI
reference.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Consolidate six duplicated helper functions (tilde_path, color_if,
split_run_path, validate_daytona_provider, format_duration_ms,
format_size) into commands/shared.rs. Also hoist Utc::now() out of a
per-run loop in list_command and avoid an unnecessary Vec<char>
allocation in truncate_goal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract generic load_config_file<T>(path, filename) helper, reducing
load_cli_config and load_server_config to one-liners.
- Rewrite WorkflowRunConfig::apply_defaults to delegate to
RunDefaults::merge_overlay, eliminating ~90 lines of duplicate
deep-merge logic. Both methods now share the same code path.
- Fix bug where RunDefaults::merge_overlay silently dropped the ssh
sandbox config from overlays (the ssh field was never merged).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests for types defined in fabro-config (HookEvent, HookDefinition,
HookConfig, McpServerConfig, McpTransport, etc.) now live alongside
their definitions rather than in the downstream re-exporting crates.
Tests for types that remain in fabro-hooks (HookContext, HookDecision,
PromptHookResponse) stay in fabro-hooks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move config/data types from upstream crates (fabro-agent, fabro-mcp,
fabro-workflows, fabro-hooks) down into fabro-config so it becomes a
leaf crate depending only on fabro-util + external crates.
New modules in fabro-config:
- mcp.rs: McpServerConfig, McpTransport, McpServerEntry
- sandbox.rs: DaytonaConfig, ExeConfig, SshConfig, SandboxConfig, etc.
- hook.rs: HookEvent, HookDefinition, HookConfig, HookType, TlsMode
- run.rs: RunDefaults, WorkflowRunConfig, LlmConfig, SetupConfig, etc.
- project.rs: ProjectConfig, workflow discovery/resolution functions
Source crates re-export from fabro-config for backward compatibility.
Also removes stale strsim dep and moves toml to dev-deps in
fabro-workflows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract set_hook_node() helper to deduplicate the 5 call sites that
populate node fields on HookContext. The helper lives in fabro-workflows
(which has the fabro-graphviz dependency) rather than fabro-hooks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the self-contained hooks module (~2900 LOC) into its own crate to
clarify the dependency graph and make the hook system independently
reusable. The set_node convenience method is inlined at its two call
sites in parallel.rs since it depends on fabro-graphviz types.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use already-imported names in run_from_branch instead of fully-qualified
fabro_interview::* paths
- Use std::io::Error::other() for serde error conversion (matches codebase
convention, more concise)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The interviewer module (trait + 7 implementations for human-in-the-loop
interactions) had zero dependencies on fabro-workflows internals, making
it a clean extraction. Consumers (fabro-api, fabro-slack) now depend on
fabro-interview directly instead of reaching through fabro-workflows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add From<ValidationError> for FabroError to eliminate duplicated
.map_err(|e| FabroError::Validation(e.0)) at call sites
- Use top-level `use` imports for stylesheet types in rules.rs
instead of verbose fully-qualified paths
- Remove duplicate parse_condition tests from fabro-workflows
(already covered by fabro-graphviz)
- Use //! inner doc comments in context/keys.rs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move validation/lint framework and all 24 rules into a dedicated
fabro-validate crate. As prerequisites, move Fidelity, stylesheet
parser/types, and condition parser into fabro-graphviz (where the
Graph types they operate on already live) so fabro-validate can
depend on fabro-graphviz directly without a circular dependency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move DaytonaSandbox into its own crate, matching the pattern used by
fabro-exe, fabro-sprites, and fabro-ssh. The new crate internalizes
daytona_sdk::Client creation so callers never touch daytona-sdk directly:
- new() is now async and creates the client internally
- reconnect(name) replaces from_existing() + manual client/get boilerplate
- daytona-sdk and daytona-api-client removed as fabro-workflows dependencies
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move retro.rs and retro_agent.rs into a new fabro-retro crate to reduce
the size of fabro-workflows and clarify domain boundaries.
Key design changes:
- Add CompletedStage struct as a flat DTO that decouples retro derivation
from Checkpoint/Outcome types in the workflow engine
- derive_retro now takes Vec<CompletedStage> (owned) instead of &Checkpoint
- run_retro_agent takes an event_callback closure instead of EventEmitter,
pushing event filtering to the caller
- Shared build_completed_stages() in fabro-workflows::lib converts
Checkpoint → Vec<CompletedStage> for both run.rs and server.rs callers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace fabro_graphviz::graph::types:: with fabro_graphviz::graph::
everywhere, since graph/mod.rs re-exports types::*. Also simplify
the From<GraphvizError> impl.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move the self-contained graph/ and parser/ modules into a new
fabro-graphviz crate so the Graphviz DOT parser can be used without
pulling in the full workflow engine.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add data attribute to confirm script execution, and delay
initialization to avoid React hydration clobbering changes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mintlify's custom TextMate grammar support doesn't work in production
builds (see mintlify/discussions#3401). Work around this with a lightweight
JS script that applies regex-based highlighting to code blocks containing
digraph definitions, matching Shiki's inline style format.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Register a separate Shiki grammar so ```fabro code blocks get
DOT syntax highlighting alongside the existing ```dot blocks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Route OpenAI OAuth users through the ChatGPT Codex backend API with
required headers (ChatGPT-Account-Id, originator). The Codex endpoint
requires streaming-only requests, omits unsupported fields (temperature,
max_output_tokens, top_p), and uses a different error format. Also
persists the account ID from OAuth tokens and updates CLI docs for
`fabro ps -q`.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the OAuth provider redirects with an error (e.g. invalid_scope),
the callback server now shows a styled error page and propagates the
error to the CLI instead of failing with a deserialization error.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>