mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-08 03:10:26 +00:00
Merge remote-tracking branch 'origin/main' into fix/root-agent-todo-projection
This commit is contained in:
commit
78718c101a
1299 changed files with 1154 additions and 500 deletions
|
|
@ -17,7 +17,7 @@ Output a report with all the bugs using this format:
|
|||
<title>title of bug</title>
|
||||
<description>brief description of bug</description>
|
||||
<location>
|
||||
<file>lib/crates/fabro-cli/src/commands/resume.rs</file>
|
||||
<file>lib/apps/fabro-cli/src/commands/resume.rs</file>
|
||||
<start_line>115</start_line>
|
||||
<end_line>115</end_line>
|
||||
</location>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Output a report with all the bugs using this format:
|
|||
<severity>important OR nit</severity>
|
||||
<pre_existing>yes OR no</pre_existing>
|
||||
<location>
|
||||
<file>lib/crates/fabro-cli/src/commands/resume.rs</file>
|
||||
<file>lib/apps/fabro-cli/src/commands/resume.rs</file>
|
||||
<start_line>115</start_line>
|
||||
<end_line>115</end_line>
|
||||
</location>
|
||||
|
|
@ -51,7 +51,7 @@ Here is a real-world example:
|
|||
<severity>important</severity>
|
||||
<pre_existing>no</pre_existing>
|
||||
<location>
|
||||
<file>lib/crates/fabro-cli/src/commands/resume.rs</file>
|
||||
<file>lib/apps/fabro-cli/src/commands/resume.rs</file>
|
||||
<start_line>208</start_line>
|
||||
<end_line>208</end_line>
|
||||
</location>
|
||||
|
|
|
|||
|
|
@ -4,32 +4,32 @@ Which source files affect which doc pages. Use this as guidance — also apply j
|
|||
|
||||
| Source | Docs |
|
||||
|--------|------|
|
||||
| `lib/crates/fabro-cli/src/main.rs`, `lib/crates/fabro-workflow/src/cli/mod.rs`, `lib/crates/fabro-workflow/src/cli/run.rs` | `docs/public/reference/cli.mdx` |
|
||||
| `lib/crates/fabro-cli/src/cli_config.rs` | `docs/public/reference/cli-configuration.mdx` |
|
||||
| `lib/crates/fabro-llm/src/cli.rs` | `docs/public/reference/cli.mdx` |
|
||||
| `lib/crates/fabro-api/src/serve.rs` | `docs/public/reference/cli.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/parser/*.rs` | `docs/public/reference/dot-language.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/condition.rs` | `docs/public/reference/dot-language.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/cli/validate.rs` | `docs/public/reference/dot-language.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/stylesheet.rs` | `docs/public/workflows/stylesheets.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/transform.rs` | `docs/public/workflows/variables.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/handler/*.rs` | `docs/public/workflows/stages-and-nodes.mdx`, `docs/public/reference/dot-language.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/handler/human.rs` | `docs/public/workflows/human-in-the-loop.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/cli/run_config.rs` | `docs/public/execution/run-configuration.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/engine.rs` | `docs/public/core-concepts/how-arc-works.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/context/*.rs` | `docs/public/execution/context.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/checkpoint.rs` | `docs/public/execution/checkpoints.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/retro.rs`, `lib/crates/fabro-workflow/src/retro_agent.rs` | `docs/public/execution/retros.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/interviewer/*.rs` | `docs/public/execution/interviews.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/hook/*.rs` | `docs/public/agents/hooks.mdx` |
|
||||
| `lib/crates/fabro-workflow/src/daytona_sandbox.rs` | `docs/public/integrations/daytona.mdx`, `docs/public/execution/environments.mdx` |
|
||||
| `lib/crates/fabro-agent/src/tools.rs`, `lib/crates/fabro-agent/src/tool_registry.rs`, `lib/crates/fabro-agent/src/tool_execution.rs` | `docs/public/agents/tools.mdx` |
|
||||
| `lib/crates/fabro-agent/src/v4a_patch.rs` | `docs/public/agents/tools.mdx` |
|
||||
| `lib/crates/fabro-agent/src/cli.rs` | `docs/public/agents/permissions.mdx` |
|
||||
| `lib/crates/fabro-agent/src/subagent.rs` | `docs/public/agents/subagents.mdx` |
|
||||
| `lib/crates/fabro-agent/src/mcp_integration.rs` | `docs/public/agents/mcp.mdx` |
|
||||
| `lib/crates/fabro-llm/src/catalog.rs`, `lib/crates/fabro-llm/src/providers/*.rs` | `docs/public/core-concepts/models.mdx` |
|
||||
| `lib/crates/fabro-slack/src/*.rs` | `docs/public/integrations/slack.mdx` |
|
||||
| `lib/crates/fabro-mcp/src/*.rs` | `docs/public/agents/mcp.mdx` |
|
||||
| `lib/crates/fabro-api/src/*.rs` | `docs/public/api-reference/overview.mdx`, `docs/public/api-reference/demo-mode.mdx` |
|
||||
| `lib/crates/fabro-api/src/server_config.rs` | `docs/public/administration/server-configuration.mdx` |
|
||||
| `lib/apps/fabro-cli/src/main.rs`, `lib/components/fabro-workflow/src/cli/mod.rs`, `lib/components/fabro-workflow/src/cli/run.rs` | `docs/public/reference/cli.mdx` |
|
||||
| `lib/apps/fabro-cli/src/cli_config.rs` | `docs/public/reference/cli-configuration.mdx` |
|
||||
| `lib/components/fabro-llm/src/cli.rs` | `docs/public/reference/cli.mdx` |
|
||||
| `lib/foundation/fabro-api/src/serve.rs` | `docs/public/reference/cli.mdx` |
|
||||
| `lib/components/fabro-workflow/src/parser/*.rs` | `docs/public/reference/dot-language.mdx` |
|
||||
| `lib/components/fabro-workflow/src/condition.rs` | `docs/public/reference/dot-language.mdx` |
|
||||
| `lib/components/fabro-workflow/src/cli/validate.rs` | `docs/public/reference/dot-language.mdx` |
|
||||
| `lib/components/fabro-workflow/src/stylesheet.rs` | `docs/public/workflows/stylesheets.mdx` |
|
||||
| `lib/components/fabro-workflow/src/transform.rs` | `docs/public/workflows/variables.mdx` |
|
||||
| `lib/components/fabro-workflow/src/handler/*.rs` | `docs/public/workflows/stages-and-nodes.mdx`, `docs/public/reference/dot-language.mdx` |
|
||||
| `lib/components/fabro-workflow/src/handler/human.rs` | `docs/public/workflows/human-in-the-loop.mdx` |
|
||||
| `lib/components/fabro-workflow/src/cli/run_config.rs` | `docs/public/execution/run-configuration.mdx` |
|
||||
| `lib/components/fabro-workflow/src/engine.rs` | `docs/public/core-concepts/how-arc-works.mdx` |
|
||||
| `lib/components/fabro-workflow/src/context/*.rs` | `docs/public/execution/context.mdx` |
|
||||
| `lib/components/fabro-workflow/src/checkpoint.rs` | `docs/public/execution/checkpoints.mdx` |
|
||||
| `lib/components/fabro-workflow/src/retro.rs`, `lib/components/fabro-workflow/src/retro_agent.rs` | `docs/public/execution/retros.mdx` |
|
||||
| `lib/components/fabro-workflow/src/interviewer/*.rs` | `docs/public/execution/interviews.mdx` |
|
||||
| `lib/components/fabro-workflow/src/hook/*.rs` | `docs/public/agents/hooks.mdx` |
|
||||
| `lib/components/fabro-workflow/src/daytona_sandbox.rs` | `docs/public/integrations/daytona.mdx`, `docs/public/execution/environments.mdx` |
|
||||
| `lib/components/fabro-agent/src/tools.rs`, `lib/components/fabro-agent/src/tool_registry.rs`, `lib/components/fabro-agent/src/tool_execution.rs` | `docs/public/agents/tools.mdx` |
|
||||
| `lib/components/fabro-agent/src/v4a_patch.rs` | `docs/public/agents/tools.mdx` |
|
||||
| `lib/components/fabro-agent/src/cli.rs` | `docs/public/agents/permissions.mdx` |
|
||||
| `lib/components/fabro-agent/src/subagent.rs` | `docs/public/agents/subagents.mdx` |
|
||||
| `lib/components/fabro-agent/src/mcp_integration.rs` | `docs/public/agents/mcp.mdx` |
|
||||
| `lib/components/fabro-llm/src/catalog.rs`, `lib/components/fabro-llm/src/providers/*.rs` | `docs/public/core-concepts/models.mdx` |
|
||||
| `lib/components/fabro-slack/src/*.rs` | `docs/public/integrations/slack.mdx` |
|
||||
| `lib/components/fabro-mcp/src/*.rs` | `docs/public/agents/mcp.mdx` |
|
||||
| `lib/foundation/fabro-api/src/*.rs` | `docs/public/api-reference/overview.mdx`, `docs/public/api-reference/demo-mode.mdx` |
|
||||
| `lib/foundation/fabro-api/src/server_config.rs` | `docs/public/administration/server-configuration.mdx` |
|
||||
|
|
|
|||
2
.gitattributes
vendored
2
.gitattributes
vendored
|
|
@ -1,2 +1,2 @@
|
|||
lib/crates/fabro-spa/assets/** linguist-generated=true -diff
|
||||
lib/apps/fabro-spa/assets/** linguist-generated=true -diff
|
||||
lib/packages/fabro-api-client/src/** linguist-generated=true
|
||||
|
|
|
|||
10
.github/workflows/rust.yml
vendored
10
.github/workflows/rust.yml
vendored
|
|
@ -4,7 +4,9 @@ on:
|
|||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "lib/crates/**"
|
||||
- "lib/apps/**"
|
||||
- "lib/components/**"
|
||||
- "lib/foundation/**"
|
||||
- "test/**"
|
||||
- "Cargo.toml"
|
||||
- "Cargo.lock"
|
||||
|
|
@ -18,7 +20,9 @@ on:
|
|||
pull_request:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "lib/crates/**"
|
||||
- "lib/apps/**"
|
||||
- "lib/components/**"
|
||||
- "lib/foundation/**"
|
||||
- "test/**"
|
||||
- "Cargo.toml"
|
||||
- "Cargo.lock"
|
||||
|
|
@ -76,7 +80,7 @@ jobs:
|
|||
- name: Verify legacy auth identity removal
|
||||
run: |
|
||||
if git grep -nE 'AuthMode::Disabled|RunAuthMethod|RunSubjectProvenance|\bActorRef\b|\bActorKind\b|AuthenticatedSubject|AuthenticatedService|AuthorizeRunScoped|AuthorizeRunBlob|AuthorizeStageArtifact|AuthorizeCommandLog|auth_method\s*==\s*"disabled"' \
|
||||
-- lib/crates apps lib/packages docs/public/api-reference/fabro-api.yaml; then
|
||||
-- lib/apps lib/components lib/foundation apps lib/packages docs/public/api-reference/fabro-api.yaml; then
|
||||
echo "::error::Legacy auth identities remain in the repository"
|
||||
exit 1
|
||||
else
|
||||
|
|
|
|||
4
.github/workflows/typescript.yml
vendored
4
.github/workflows/typescript.yml
vendored
|
|
@ -5,7 +5,7 @@ on:
|
|||
branches: [main]
|
||||
paths:
|
||||
- "apps/**"
|
||||
- "lib/crates/fabro-spa/**"
|
||||
- "lib/apps/fabro-spa/**"
|
||||
- "lib/packages/**"
|
||||
- "package.json"
|
||||
- "bun.lock"
|
||||
|
|
@ -17,7 +17,7 @@ on:
|
|||
branches: [main]
|
||||
paths:
|
||||
- "apps/**"
|
||||
- "lib/crates/fabro-spa/**"
|
||||
- "lib/apps/fabro-spa/**"
|
||||
- "lib/packages/**"
|
||||
- "package.json"
|
||||
- "bun.lock"
|
||||
|
|
|
|||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -4,8 +4,8 @@ target
|
|||
node_modules
|
||||
apps/fabro-web/dist
|
||||
apps/fabro-web/.dist-builds/
|
||||
lib/crates/fabro-spa/assets/*
|
||||
!lib/crates/fabro-spa/assets/.gitkeep
|
||||
lib/apps/fabro-spa/assets/*
|
||||
!lib/apps/fabro-spa/assets/.gitkeep
|
||||
tmp
|
||||
evals/swe-bench/repos/
|
||||
evals/swe-bench/results/
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ The OpenAPI spec at `docs/public/api-reference/fabro-api.yaml` is the source of
|
|||
|
||||
1. Edit `docs/public/api-reference/fabro-api.yaml`
|
||||
2. `cargo build -p fabro-api` — build.rs regenerates Rust types and client via progenitor
|
||||
3. Write/update handler in `lib/crates/fabro-server/src/server.rs`, add route to `build_router()`
|
||||
3. Write/update handler in `lib/apps/fabro-server/src/server.rs`, add route to `build_router()`
|
||||
4. `cargo nextest run -p fabro-server` — conformance test catches spec/router drift
|
||||
5. `cd lib/packages/fabro-api-client && bun run generate` — regenerates TypeScript Axios client
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ The OpenAPI spec at `docs/public/api-reference/fabro-api.yaml` is the source of
|
|||
|
||||
- Treat OpenAPI as the source of truth for the wire contract, not as the automatic owner of Rust types.
|
||||
- Before adding or keeping a generated schema type, search the workspace for an existing hand-written Rust type with the same product meaning.
|
||||
- If the schema and an existing Rust type have the same semantics and serde shape, reuse the existing type via `lib/crates/fabro-api/build.rs` `with_replacement(...)` instead of generating a parallel API type.
|
||||
- If the schema and an existing Rust type have the same semantics and serde shape, reuse the existing type via `lib/foundation/fabro-api/build.rs` `with_replacement(...)` instead of generating a parallel API type.
|
||||
- If two types are close but not identical, prefer proposing changes that align them into one canonical type rather than accepting small drift. It is usually better to iterate the API now than to create permanently split Rust/API types.
|
||||
- Keep a separate API DTO only when the API is intentionally a projection, summary, or presentation-specific view of internal state. In that case, give it a distinct API-facing name instead of reusing the internal concept name.
|
||||
- Treat `ApiFoo` aliases and `foo_to_api` / `foo_from_api` adapters as a smell unless they represent a real semantic boundary. They should not exist only to bridge accidental duplicate types.
|
||||
|
|
@ -107,7 +107,7 @@ Before merging changes that add or move shared test helpers, verify:
|
|||
|
||||
Fabro is an AI-powered workflow orchestration platform. Workflows are defined as Graphviz graphs, where each node is a stage (agent, prompt, command, conditional, human, parallel, etc.) executed by the workflow engine.
|
||||
|
||||
### Rust crates (`lib/crates/`)
|
||||
### Rust crates (`lib/apps/`, `lib/components/`, and `lib/foundation/`)
|
||||
- **fabro-cli** — CLI entry point. Commands: `run`, `exec`, `serve`, `validate`, `parse`, `cp`, `model`, `doctor`, `install`, `ps`, `system prune`
|
||||
- **fabro-workflow** — Core workflow engine. Parses Graphviz graphs, runs stages, manages checkpoints/resume, hooks, and human-in-the-loop interactions
|
||||
- **fabro-agent** — AI coding agent with tool use (Bash, Read, Write, Edit, Glob, Grep, WebFetch). `Sandbox` trait abstracts execution environments
|
||||
|
|
|
|||
22
Cargo.toml
22
Cargo.toml
|
|
@ -1,6 +1,12 @@
|
|||
[workspace]
|
||||
members = ["lib/crates/*", "test/twin/openai", "test/twin/github"]
|
||||
default-members = ["lib/crates/fabro-cli"]
|
||||
members = [
|
||||
"lib/apps/*",
|
||||
"lib/components/*",
|
||||
"lib/foundation/*",
|
||||
"test/twin/openai",
|
||||
"test/twin/github",
|
||||
]
|
||||
default-members = ["lib/apps/fabro-cli"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
|
|
@ -84,7 +90,7 @@ hmac = "0.12"
|
|||
sha2 = "0.10"
|
||||
hex = "0.4"
|
||||
insta = "1"
|
||||
fabro-test = { path = "lib/crates/fabro-test" }
|
||||
fabro-test = { path = "lib/foundation/fabro-test" }
|
||||
twin-openai = { path = "test/twin/openai" }
|
||||
twin-github = { path = "test/twin/github" }
|
||||
tokio-tungstenite = { version = "0.26", features = ["rustls-tls-webpki-roots"] }
|
||||
|
|
@ -100,11 +106,11 @@ rust-embed = "8"
|
|||
percent-encoding = "2"
|
||||
minijinja = "=2.19.0"
|
||||
miette = { version = "7.6", features = ["fancy"] }
|
||||
fabro-http = { path = "lib/crates/fabro-http" }
|
||||
fabro-environment = { path = "lib/crates/fabro-environment" }
|
||||
fabro-options-metadata = { path = "lib/crates/fabro-options-metadata" }
|
||||
fabro-redact = { path = "lib/crates/fabro-redact" }
|
||||
fabro-static = { path = "lib/crates/fabro-static" }
|
||||
fabro-http = { path = "lib/foundation/fabro-http" }
|
||||
fabro-environment = { path = "lib/components/fabro-environment" }
|
||||
fabro-options-metadata = { path = "lib/foundation/fabro-options-metadata" }
|
||||
fabro-redact = { path = "lib/foundation/fabro-redact" }
|
||||
fabro-static = { path = "lib/foundation/fabro-static" }
|
||||
graphviz-sys = { git = "https://github.com/fabro-sh/graphviz-sys" }
|
||||
ref-cast = "1"
|
||||
strum = { version = "0.28", features = ["derive"] }
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export const handle = { wide: true, fullHeight: true };
|
|||
|
||||
type Direction = "LR" | "TB";
|
||||
|
||||
// Mirrors fabro-graphviz's RANKDIR_RE (lib/crates/fabro-graphviz/src/render.rs) —
|
||||
// Mirrors fabro-graphviz's RANKDIR_RE (lib/components/fabro-graphviz/src/render.rs) —
|
||||
// keep the accepted `rankdir=` syntax in sync with that regex.
|
||||
const RANKDIR_RE = /rankdir\s*=\s*(\w+)/;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Scope
|
||||
|
||||
- Production imports under `lib/crates/fabro-cli/src/**` that still reference `fabro_workflow::*` after the server-owned selector/export refactor.
|
||||
- Production imports under `lib/apps/fabro-cli/src/**` that still reference `fabro_workflow::*` after the server-owned selector/export refactor.
|
||||
- Test-only imports are listed separately so the remaining architectural debt is explicit.
|
||||
|
||||
## Completed In This Change
|
||||
|
|
@ -16,30 +16,30 @@
|
|||
|
||||
| Path | Direct dependency | Why it still exists | Required remediation track |
|
||||
| --- | --- | --- | --- |
|
||||
| `lib/crates/fabro-cli/src/commands/pr/create.rs` | `StageOutcome`, `pull_request::maybe_open_pull_request` | CLI still reconstructs store state and runs PR creation logic from the workflow pipeline directly. | Replace with a server API, or extract PR orchestration into a non-engine shared service crate plus API. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/runner.rs` | `artifact_snapshot::CapturedArtifactInfo`, `artifact_upload::{ArtifactSink, StageArtifactUploader}`, `event::{Emitter, RunEventSink}`, `operations::{self, StartServices}`, `run_control::RunControlState`, `runtime_store::{RunStoreBackend, RunStoreHandle}` | Hidden worker subprocess path still lives inside the CLI crate and embeds the workflow engine directly. | Re-home worker/runtime code outside the user CLI surface, ideally into a dedicated worker crate or binary. |
|
||||
| `lib/crates/fabro-cli/src/manifest_builder.rs` | `git::{GitSyncStatus, head_sha, sync_status}` | Manifest submission still relies on git helper logic that happens to live in `fabro_workflow`. | Extract git-sync inspection helpers into a non-workflow shared crate/module. |
|
||||
| `lib/crates/fabro-cli/src/server_client.rs` | `artifact_snapshot::CapturedArtifactInfo` | The upload client reuses a workflow-owned artifact snapshot DTO. | Extract shared artifact snapshot DTOs into `fabro-store`, `fabro-types`, or a dedicated shared crate. |
|
||||
| `lib/crates/fabro-cli/src/commands/runs/inspect.rs` | `run_status::RunStatus` | CLI output types still depend on engine-owned run status enums. | Extract shared status types into `fabro-types` or switch to API-generated/public store types. |
|
||||
| `lib/crates/fabro-cli/src/commands/runs/list.rs` | `run_status::RunStatus` | List rendering still depends on engine-owned run status enums. | Extract shared status types into `fabro-types` or switch to API-generated/public store types. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/attach.rs` | `StageOutcome`, `run_status::RunStatus` | Attach/replay logic still formats engine-owned terminal status types directly. | Extract shared run/conclusion status types into `fabro-types`. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/output.rs` | `StageOutcome`, `records::Conclusion` | Human-readable completion output still consumes workflow-owned conclusion/status records. | Extract shared conclusion/status DTOs into `fabro-types` or `fabro-store`. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/wait.rs` | `records::Conclusion`, `run_status::RunStatus` | Wait output still depends on workflow-owned status/conclusion records. | Extract shared conclusion/status DTOs into `fabro-types` or `fabro-store`. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/run_progress/stage_display.rs` | `StageOutcome`, `format_cost` | Progress UI still depends on shared stage outcome and workflow-owned cost-formatting helper code. | Move formatting helpers into `fabro-util`. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/run_progress/info_display.rs` | `event::RunNoticeLevel` | Progress UI still formats workflow-owned notice levels directly. | Extract shared notice/event enums into `fabro-types`. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/run_progress/event.rs` | `event::RunNoticeLevel` | Progress event translation still depends on workflow-owned notice levels. | Extract shared notice/event enums into `fabro-types`. |
|
||||
| `lib/apps/fabro-cli/src/commands/pr/create.rs` | `StageOutcome`, `pull_request::maybe_open_pull_request` | CLI still reconstructs store state and runs PR creation logic from the workflow pipeline directly. | Replace with a server API, or extract PR orchestration into a non-engine shared service crate plus API. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/runner.rs` | `artifact_snapshot::CapturedArtifactInfo`, `artifact_upload::{ArtifactSink, StageArtifactUploader}`, `event::{Emitter, RunEventSink}`, `operations::{self, StartServices}`, `run_control::RunControlState`, `runtime_store::{RunStoreBackend, RunStoreHandle}` | Hidden worker subprocess path still lives inside the CLI crate and embeds the workflow engine directly. | Re-home worker/runtime code outside the user CLI surface, ideally into a dedicated worker crate or binary. |
|
||||
| `lib/apps/fabro-cli/src/manifest_builder.rs` | `git::{GitSyncStatus, head_sha, sync_status}` | Manifest submission still relies on git helper logic that happens to live in `fabro_workflow`. | Extract git-sync inspection helpers into a non-workflow shared crate/module. |
|
||||
| `lib/apps/fabro-cli/src/server_client.rs` | `artifact_snapshot::CapturedArtifactInfo` | The upload client reuses a workflow-owned artifact snapshot DTO. | Extract shared artifact snapshot DTOs into `fabro-store`, `fabro-types`, or a dedicated shared crate. |
|
||||
| `lib/apps/fabro-cli/src/commands/runs/inspect.rs` | `run_status::RunStatus` | CLI output types still depend on engine-owned run status enums. | Extract shared status types into `fabro-types` or switch to API-generated/public store types. |
|
||||
| `lib/apps/fabro-cli/src/commands/runs/list.rs` | `run_status::RunStatus` | List rendering still depends on engine-owned run status enums. | Extract shared status types into `fabro-types` or switch to API-generated/public store types. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/attach.rs` | `StageOutcome`, `run_status::RunStatus` | Attach/replay logic still formats engine-owned terminal status types directly. | Extract shared run/conclusion status types into `fabro-types`. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/output.rs` | `StageOutcome`, `records::Conclusion` | Human-readable completion output still consumes workflow-owned conclusion/status records. | Extract shared conclusion/status DTOs into `fabro-types` or `fabro-store`. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/wait.rs` | `records::Conclusion`, `run_status::RunStatus` | Wait output still depends on workflow-owned status/conclusion records. | Extract shared conclusion/status DTOs into `fabro-types` or `fabro-store`. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/run_progress/stage_display.rs` | `StageOutcome`, `format_cost` | Progress UI still depends on shared stage outcome and workflow-owned cost-formatting helper code. | Move formatting helpers into `fabro-util`. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/run_progress/info_display.rs` | `event::RunNoticeLevel` | Progress UI still formats workflow-owned notice levels directly. | Extract shared notice/event enums into `fabro-types`. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/run_progress/event.rs` | `event::RunNoticeLevel` | Progress event translation still depends on workflow-owned notice levels. | Extract shared notice/event enums into `fabro-types`. |
|
||||
|
||||
## Test-Only Couplings
|
||||
|
||||
| Path | Direct dependency | Why it still exists | Suggested handling |
|
||||
| --- | --- | --- | --- |
|
||||
| `lib/crates/fabro-cli/src/commands/dump.rs` test module | `event::{Event, append_event}` | Unit tests synthesize workflow events directly. | Low priority; keep until a lighter-weight event fixture helper exists. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/wait.rs` test module | `StageOutcome`, `records::Conclusion`, `run_status::RunStatusRecord` | Output tests construct workflow-owned records directly. | Replace with shared fixture builders once conclusion DTOs move out. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/run_progress/mod.rs` test module | `event::{Event, RunNoticeLevel, to_run_event, to_run_event_at}`, `outcome::billed_model_usage_from_llm` | Progress tests build engine events directly. | Replace with shared event fixture helpers after event DTO extraction. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/run_progress/event.rs` test module | `event::{Event, to_run_event}` | Event rendering tests depend on engine event constructors. | Replace with shared event fixture helpers after event DTO extraction. |
|
||||
| `lib/crates/fabro-cli/src/commands/run/runner.rs` test module | `artifact_upload::StageArtifactUploader` | Worker tests still reach into workflow upload internals. | Keep with worker re-home work; not worth separating first. |
|
||||
| `lib/crates/fabro-cli/tests/it/workflow/real_cli.rs` | `context::Context`, `event::Emitter`, `handler::agent::{CodergenBackend, CodergenResult}`, `handler::llm::cli::AgentCliBackend` | Integration test exercises the real workflow engine directly through CLI harnesses. | Accept as engine integration coverage or move under workflow-owned test support later. |
|
||||
| `lib/crates/fabro-cli/tests/it/scenario/recovery.rs` | `operations::{RunTimeline, build_timeline}` | Scenario test inspects rewind timeline internals directly. | Replace after server-owned rewind/timeline APIs exist. |
|
||||
| `lib/apps/fabro-cli/src/commands/dump.rs` test module | `event::{Event, append_event}` | Unit tests synthesize workflow events directly. | Low priority; keep until a lighter-weight event fixture helper exists. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/wait.rs` test module | `StageOutcome`, `records::Conclusion`, `run_status::RunStatusRecord` | Output tests construct workflow-owned records directly. | Replace with shared fixture builders once conclusion DTOs move out. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/run_progress/mod.rs` test module | `event::{Event, RunNoticeLevel, to_run_event, to_run_event_at}`, `outcome::billed_model_usage_from_llm` | Progress tests build engine events directly. | Replace with shared event fixture helpers after event DTO extraction. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/run_progress/event.rs` test module | `event::{Event, to_run_event}` | Event rendering tests depend on engine event constructors. | Replace with shared event fixture helpers after event DTO extraction. |
|
||||
| `lib/apps/fabro-cli/src/commands/run/runner.rs` test module | `artifact_upload::StageArtifactUploader` | Worker tests still reach into workflow upload internals. | Keep with worker re-home work; not worth separating first. |
|
||||
| `lib/apps/fabro-cli/tests/it/workflow/real_cli.rs` | `context::Context`, `event::Emitter`, `handler::agent::{CodergenBackend, CodergenResult}`, `handler::llm::cli::AgentCliBackend` | Integration test exercises the real workflow engine directly through CLI harnesses. | Accept as engine integration coverage or move under workflow-owned test support later. |
|
||||
| `lib/apps/fabro-cli/tests/it/scenario/recovery.rs` | `operations::{RunTimeline, build_timeline}` | Scenario test inspects rewind timeline internals directly. | Replace after server-owned rewind/timeline APIs exist. |
|
||||
|
||||
## Follow-Up Order
|
||||
|
||||
|
|
|
|||
|
|
@ -48,9 +48,9 @@ That envelope is stronger than most comparator systems. It gives Fabro stable to
|
|||
Relevant current Fabro sources:
|
||||
|
||||
- `docs-internal/events-strategy.md`
|
||||
- `lib/crates/fabro-workflow/src/event.rs`
|
||||
- `lib/crates/fabro-types/src/run_event/mod.rs`
|
||||
- `lib/crates/fabro-agent/src/types.rs`
|
||||
- `lib/components/fabro-workflow/src/event.rs`
|
||||
- `lib/foundation/fabro-types/src/run_event/mod.rs`
|
||||
- `lib/components/fabro-agent/src/types.rs`
|
||||
|
||||
## Comparison Matrix
|
||||
|
||||
|
|
|
|||
|
|
@ -269,21 +269,21 @@ The durable model remains simple: replay ordered events, no duplicate truth laye
|
|||
|
||||
An engineer implementing this proposal should make only these structural changes unless a later section explicitly says otherwise.
|
||||
|
||||
1. Update [`RunEvent`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/mod.rs) to add:
|
||||
1. Update [`RunEvent`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/mod.rs) to add:
|
||||
- `stage_id`
|
||||
- `parallel_group_id`
|
||||
- `parallel_branch_id`
|
||||
- `tool_call_id`
|
||||
- `actor`
|
||||
2. Update `RunEvent::to_value()` and `RunEvent` parsing in [`run_event/mod.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/mod.rs) so the new envelope fields serialize and deserialize.
|
||||
3. Extend `StoredEventFields` and `stored_event_fields()` in [`event.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-workflow/src/event.rs) to populate:
|
||||
2. Update `RunEvent::to_value()` and `RunEvent` parsing in [`run_event/mod.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/mod.rs) so the new envelope fields serialize and deserialize.
|
||||
3. Extend `StoredEventFields` and `stored_event_fields()` in [`event.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/components/fabro-workflow/src/event.rs) to populate:
|
||||
- `stage_id`
|
||||
- `parallel_group_id`
|
||||
- `parallel_branch_id`
|
||||
- `tool_call_id` on tool-lifecycle events
|
||||
- `actor` when there is a clear primary actor
|
||||
These values should come from the emitter's current execution context for stage and parallel scope, and from event-specific payloads for `tool_call_id`.
|
||||
4. Leave [`EventEnvelope`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-store/src/types.rs) structurally unchanged:
|
||||
4. Leave [`EventEnvelope`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/components/fabro-store/src/types.rs) structurally unchanged:
|
||||
- `seq: u32`
|
||||
- `payload: EventPayload`
|
||||
5. Update API/SSE envelope serialization so wire JSON is flattened:
|
||||
|
|
@ -304,11 +304,11 @@ An engineer implementing this proposal should make only these structural changes
|
|||
|
||||
V2 should keep the current hand-coded domain split for prop structs:
|
||||
|
||||
- run props in [`run.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/run.rs)
|
||||
- stage and checkpoint props in [`stage.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/stage.rs)
|
||||
- agent props in [`agent.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/agent.rs)
|
||||
- infra/setup props in [`infra.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/infra.rs)
|
||||
- parallel/interview/git/misc props in [`misc.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/crates/fabro-types/src/run_event/misc.rs)
|
||||
- run props in [`run.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/run.rs)
|
||||
- stage and checkpoint props in [`stage.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/stage.rs)
|
||||
- agent props in [`agent.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/agent.rs)
|
||||
- infra/setup props in [`infra.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/infra.rs)
|
||||
- parallel/interview/git/misc props in [`misc.rs`](/Users/bhelmkamp/p/fabro-sh/fabro/lib/foundation/fabro-types/src/run_event/misc.rs)
|
||||
|
||||
That split is part of the design quality. V2 should keep adding hand-coded prop structs, not collapse everything into generic maps.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Fabro MCP Server — QA Test Plan
|
||||
|
||||
One-time manual QA pass for the 5 tools exposed by `fabro-mcp-server`. Source of truth: `lib/crates/fabro-mcp-server/src/run_tools/`.
|
||||
One-time manual QA pass for the 5 tools exposed by `fabro-mcp-server`. Source of truth: `lib/apps/fabro-mcp-server/src/run_tools/`.
|
||||
|
||||
This plan is **not** a template for adding automated test coverage — it exists to drive a single hands-on sweep against a real running server. Tick boxes as scenarios pass; add notes inline for failures or surprising behavior. Open bugs/PRs for issues found; do not port these scenarios into the Rust test suite.
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Migrations are product-facing compatibility code. Treat them like startup and st
|
|||
Each crate owns the migrations for the data it owns.
|
||||
|
||||
```text
|
||||
lib/crates/<crate>/
|
||||
lib/<layer>/<crate>/
|
||||
migrations/
|
||||
YYYYMMDDSS_descriptive_name.rs
|
||||
src/migrations.rs
|
||||
|
|
|
|||
|
|
@ -170,14 +170,14 @@ Required payload fields:
|
|||
|
||||
Emit from the same places that currently call `put_status`:
|
||||
|
||||
- `lib/crates/fabro-workflow/src/operations/create.rs`
|
||||
- `lib/crates/fabro-workflow/src/operations/start.rs`
|
||||
- `lib/crates/fabro-workflow/src/operations/resume.rs`
|
||||
- `lib/crates/fabro-workflow/src/pipeline/finalize.rs`
|
||||
- `lib/crates/fabro-workflow/src/lifecycle/disk.rs`
|
||||
- `lib/components/fabro-workflow/src/operations/create.rs`
|
||||
- `lib/components/fabro-workflow/src/operations/start.rs`
|
||||
- `lib/components/fabro-workflow/src/operations/resume.rs`
|
||||
- `lib/components/fabro-workflow/src/pipeline/finalize.rs`
|
||||
- `lib/components/fabro-workflow/src/lifecycle/disk.rs`
|
||||
- CLI administrative flows that directly mutate status:
|
||||
- `lib/crates/fabro-cli/src/commands/runs/rm.rs`
|
||||
- `lib/crates/fabro-cli/src/commands/run/rewind.rs`
|
||||
- `lib/apps/fabro-cli/src/commands/runs/rm.rs`
|
||||
- `lib/apps/fabro-cli/src/commands/run/rewind.rs`
|
||||
|
||||
### 2. Enrich `checkpoint.completed` to carry a full checkpoint snapshot
|
||||
|
||||
|
|
@ -200,11 +200,11 @@ Add fields covering:
|
|||
|
||||
Emitter seam:
|
||||
|
||||
- `lib/crates/fabro-workflow/src/lifecycle/event.rs`
|
||||
- `lib/components/fabro-workflow/src/lifecycle/event.rs`
|
||||
|
||||
Producer seam for the source checkpoint object:
|
||||
|
||||
- `lib/crates/fabro-workflow/src/lifecycle/disk.rs`
|
||||
- `lib/components/fabro-workflow/src/lifecycle/disk.rs`
|
||||
|
||||
Design rule:
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ Add:
|
|||
|
||||
Producer seam:
|
||||
|
||||
- `lib/crates/fabro-workflow/src/pipeline/pull_request.rs`
|
||||
- `lib/components/fabro-workflow/src/pipeline/pull_request.rs`
|
||||
|
||||
After this lands, `put_pull_request` should become removable during the later memoized-state cutover.
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ Do not add a separate storage-shaped event. The final patch is run-level termina
|
|||
|
||||
Enrich `run.completed`, using the patch already computed from:
|
||||
|
||||
- `lib/crates/fabro-workflow/src/lifecycle/git.rs`
|
||||
- `lib/components/fabro-workflow/src/lifecycle/git.rs`
|
||||
|
||||
Required payload:
|
||||
|
||||
|
|
@ -287,9 +287,9 @@ Required projected output:
|
|||
|
||||
Likely seams:
|
||||
|
||||
- `lib/crates/fabro-workflow/src/handler/agent.rs`
|
||||
- `lib/crates/fabro-workflow/src/handler/llm/api.rs`
|
||||
- `lib/crates/fabro-workflow/src/pipeline/retro.rs` if retro uses the same forwarded agent session path
|
||||
- `lib/components/fabro-workflow/src/handler/agent.rs`
|
||||
- `lib/components/fabro-workflow/src/handler/llm/api.rs`
|
||||
- `lib/components/fabro-workflow/src/pipeline/retro.rs` if retro uses the same forwarded agent session path
|
||||
- any CLI-backed LLM path if it still produces `provider_used.json`
|
||||
|
||||
Do not keep the current “read JSON sidecar, then `put_node_provider_used`” pattern once this event exists.
|
||||
|
|
@ -304,7 +304,7 @@ Use the existing terminal parallel event rather than adding a storage-shaped eve
|
|||
|
||||
Add to `parallel.completed`, emitted from:
|
||||
|
||||
- `lib/crates/fabro-workflow/src/handler/parallel.rs`
|
||||
- `lib/components/fabro-workflow/src/handler/parallel.rs`
|
||||
|
||||
Required new payload:
|
||||
|
||||
|
|
@ -346,19 +346,19 @@ Likely files to touch:
|
|||
- `docs-internal/events.md`
|
||||
- `docs-internal/run-directory-keys.md`
|
||||
- `docs-internal/events-strategy.md`
|
||||
- `lib/crates/fabro-workflow/src/event.rs`
|
||||
- `lib/crates/fabro-workflow/src/lifecycle/event.rs`
|
||||
- `lib/crates/fabro-workflow/src/lifecycle/disk.rs`
|
||||
- `lib/crates/fabro-workflow/src/lifecycle/git.rs`
|
||||
- `lib/crates/fabro-workflow/src/operations/create.rs`
|
||||
- `lib/crates/fabro-workflow/src/operations/start.rs`
|
||||
- `lib/crates/fabro-workflow/src/operations/resume.rs`
|
||||
- `lib/crates/fabro-workflow/src/pipeline/finalize.rs`
|
||||
- `lib/crates/fabro-workflow/src/pipeline/pull_request.rs`
|
||||
- `lib/crates/fabro-workflow/src/handler/agent.rs`
|
||||
- `lib/crates/fabro-workflow/src/handler/parallel.rs`
|
||||
- `lib/crates/fabro-cli/src/commands/runs/rm.rs`
|
||||
- `lib/crates/fabro-cli/src/commands/run/rewind.rs`
|
||||
- `lib/components/fabro-workflow/src/event.rs`
|
||||
- `lib/components/fabro-workflow/src/lifecycle/event.rs`
|
||||
- `lib/components/fabro-workflow/src/lifecycle/disk.rs`
|
||||
- `lib/components/fabro-workflow/src/lifecycle/git.rs`
|
||||
- `lib/components/fabro-workflow/src/operations/create.rs`
|
||||
- `lib/components/fabro-workflow/src/operations/start.rs`
|
||||
- `lib/components/fabro-workflow/src/operations/resume.rs`
|
||||
- `lib/components/fabro-workflow/src/pipeline/finalize.rs`
|
||||
- `lib/components/fabro-workflow/src/pipeline/pull_request.rs`
|
||||
- `lib/components/fabro-workflow/src/handler/agent.rs`
|
||||
- `lib/components/fabro-workflow/src/handler/parallel.rs`
|
||||
- `lib/apps/fabro-cli/src/commands/runs/rm.rs`
|
||||
- `lib/apps/fabro-cli/src/commands/run/rewind.rs`
|
||||
- tests in `fabro-workflow`, `fabro-cli`, and `fabro-store`
|
||||
|
||||
## Phases
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ This document maps the files that still live under a run scratch directory. Dura
|
|||
Scope:
|
||||
- Scratch root: `~/.fabro/scratch/YYYYMMDD-{run_id}/`
|
||||
- This covers local run files only
|
||||
- Persistent store keys live in `lib/crates/fabro-store/src/keys.rs`
|
||||
- Artifact object-store keys live in `lib/crates/fabro-store/src/artifact_store.rs`
|
||||
- Persistent store keys live in `lib/components/fabro-store/src/keys.rs`
|
||||
- Artifact object-store keys live in `lib/components/fabro-store/src/artifact_store.rs`
|
||||
|
||||
There is no `_init.json` anymore. Run existence in the database is determined by stored run events, and local scratch directories are managed separately under `scratch/`.
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ Method:
|
|||
### [x] 1. Change two slow `exec` mock responses from retriable `500` to non-retriable `400`
|
||||
|
||||
Files:
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/exec.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/exec.rs`
|
||||
|
||||
Measured evidence:
|
||||
- `fabro-cli::it::cmd::exec::exec_cli_server_target_overrides_configured_server_target`: `6.858s` median
|
||||
|
|
@ -32,7 +32,7 @@ Measured evidence:
|
|||
- mocked `400`: `0.053s` median
|
||||
|
||||
Implementation status:
|
||||
- Implemented in `lib/crates/fabro-cli/tests/it/cmd/exec.rs`
|
||||
- Implemented in `lib/apps/fabro-cli/tests/it/cmd/exec.rs`
|
||||
- Verified with `ulimit -n 4096` via 5 targeted nextest runs per test
|
||||
- Post-change nextest exec-time medians:
|
||||
- `exec_server_target_uses_remote_transport_instead_of_local_api_key_resolution`: `1.580s`
|
||||
|
|
@ -57,7 +57,7 @@ Cons:
|
|||
### 2. Short-circuit delete-path worker grace for already-terminal runs
|
||||
|
||||
Files:
|
||||
- `lib/crates/fabro-server/src/server.rs`
|
||||
- `lib/apps/fabro-server/src/server.rs`
|
||||
|
||||
Measured evidence:
|
||||
- `fabro-cli::it::cmd::system_prune::system_prune_yes_deletes_matching_runs`: `10.477s`
|
||||
|
|
@ -87,11 +87,11 @@ Cons:
|
|||
### [x] 3. Collapse the five abnormally slow `help` integration tests into one smoke test or a lighter harness
|
||||
|
||||
Files:
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/artifact.rs`
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/artifact_list.rs`
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/artifact_cp.rs`
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/config.rs`
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/artifact.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/artifact_list.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/artifact_cp.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/config.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
|
||||
|
||||
Measured evidence:
|
||||
- Slow `help` tests:
|
||||
|
|
@ -131,8 +131,8 @@ Cons:
|
|||
### [x] 4. Replace `doctor_no_color_when_no_color_set` with a render-path assertion
|
||||
|
||||
Files:
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/doctor.rs`
|
||||
- `lib/crates/fabro-util/src/check_report.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/doctor.rs`
|
||||
- `lib/foundation/fabro-util/src/check_report.rs`
|
||||
|
||||
Measured evidence:
|
||||
- `fabro-cli::it::cmd::doctor::doctor_no_color_when_no_color_set`: `5.131s`
|
||||
|
|
@ -144,7 +144,7 @@ Estimated impact:
|
|||
|
||||
Implementation status:
|
||||
- Implemented by deleting `fabro-cli::it::cmd::doctor::doctor_no_color_when_no_color_set`
|
||||
- Added a unit-level render assertion in `lib/crates/fabro-cli/src/commands/doctor.rs`:
|
||||
- Added a unit-level render assertion in `lib/apps/fabro-cli/src/commands/doctor.rs`:
|
||||
- `render_report_text_without_color_has_no_ansi`
|
||||
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli render_report_text_without_color_has_no_ansi --status-level fail --final-status-level fail --show-progress none`
|
||||
- Verification result: `1 passed`
|
||||
|
|
@ -166,8 +166,8 @@ Cons:
|
|||
### [x] 5. Fix local Unix-socket autostart so it doesn't burn the full 5s readiness wait
|
||||
|
||||
Files:
|
||||
- `lib/crates/fabro-cli/src/server_client.rs`
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/server_start.rs`
|
||||
- `lib/apps/fabro-cli/src/server_client.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/server_start.rs`
|
||||
|
||||
Measured evidence:
|
||||
- Pre-fix 5-run timing for `fabro-cli::it::cmd::server_start::concurrent_autostart_converges_on_one_shared_daemon_and_cleans_up`:
|
||||
|
|
@ -197,7 +197,7 @@ Implementation status:
|
|||
- Implemented by splitting the Unix-socket connection path into:
|
||||
- a single immediate health probe before autostart
|
||||
- the existing retrying readiness wait after autostart
|
||||
- Kept the original integration test coverage in `lib/crates/fabro-cli/tests/it/cmd/server_start.rs`
|
||||
- Kept the original integration test coverage in `lib/apps/fabro-cli/tests/it/cmd/server_start.rs`
|
||||
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli concurrent_autostart_converges_on_one_shared_daemon_and_cleans_up --status-level fail --final-status-level fail --show-progress none`
|
||||
- Verification result: `1 passed`
|
||||
- Post-change 5-run timing for `fabro-cli::it::cmd::server_start::concurrent_autostart_converges_on_one_shared_daemon_and_cleans_up`:
|
||||
|
|
@ -217,7 +217,7 @@ Implementation status:
|
|||
### [x] 6. Collapse three lightweight `attach` smoke tests into one scenario-style test
|
||||
|
||||
Files:
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
|
||||
|
||||
Measured evidence:
|
||||
- `attach_requires_run_arg`: `1.595s`
|
||||
|
|
@ -230,7 +230,7 @@ Estimated impact:
|
|||
- Conservative recoverable time: about `3.15s`
|
||||
|
||||
Implementation status:
|
||||
- Implemented by removing the 3 command-owned smoke tests from `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
|
||||
- Implemented by removing the 3 command-owned smoke tests from `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
|
||||
- Added `fabro-cli::it::scenario::smoke::attach_smoke_covers_arg_validation_and_remote_server_behaviors`
|
||||
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli attach_smoke_covers_arg_validation_and_remote_server_behaviors --status-level fail --final-status-level fail --show-progress none`
|
||||
- Verification result: `1 passed`
|
||||
|
|
@ -256,7 +256,7 @@ Cons:
|
|||
### [x] 7. Collapse the three `completion` tests
|
||||
|
||||
Files:
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/completion.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/completion.rs`
|
||||
|
||||
Measured evidence:
|
||||
- `completion::generates_zsh_completions`: `1.567s`
|
||||
|
|
@ -295,7 +295,7 @@ Cons:
|
|||
### [x] 8. Remove or merge the duplicate attach replay test
|
||||
|
||||
Files:
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
|
||||
|
||||
Measured evidence:
|
||||
- `attach_replays_completed_detached_run`: `2.696s`
|
||||
|
|
@ -303,7 +303,7 @@ Measured evidence:
|
|||
- The two tests are currently identical in code and assertions
|
||||
|
||||
Implementation status:
|
||||
- Implemented by removing the duplicate test from `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
|
||||
- Implemented by removing the duplicate test from `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
|
||||
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli attach_replays_completed_detached_run --status-level fail --final-status-level fail --show-progress none`
|
||||
- Verification result: `1 passed`
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ Cons:
|
|||
### [x] 9. Make `attach_before_completion_streams_to_finished_state` event-driven instead of sleep-driven
|
||||
|
||||
Files:
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
|
||||
|
||||
Measured evidence:
|
||||
- `attach_before_completion_streams_to_finished_state`: `3.043s`
|
||||
|
|
@ -333,7 +333,7 @@ Measured evidence:
|
|||
- `write_gated_workflow()` adds another fixed `sleep 0.2`
|
||||
|
||||
Implementation status:
|
||||
- Implemented by replacing the fixed 1-second gate-release sleep with a real attach-output signal in `lib/crates/fabro-cli/tests/it/cmd/attach.rs`
|
||||
- Implemented by replacing the fixed 1-second gate-release sleep with a real attach-output signal in `lib/apps/fabro-cli/tests/it/cmd/attach.rs`
|
||||
- The test now spawns `fabro attach`, waits for replayed stderr output (`✓ start`), then releases the workflow gate
|
||||
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli attach_before_completion_streams_to_finished_state --status-level fail --final-status-level fail --show-progress none`
|
||||
- Verification result: `1 passed`
|
||||
|
|
@ -361,14 +361,14 @@ Cons:
|
|||
### [x] 10. Remove or parameterize the fixed `sleep 0.2` in `write_gated_workflow()`
|
||||
|
||||
Files:
|
||||
- `lib/crates/fabro-cli/tests/it/cmd/support.rs`
|
||||
- `lib/apps/fabro-cli/tests/it/cmd/support.rs`
|
||||
|
||||
Measured evidence:
|
||||
- `write_gated_workflow()` hardcodes `sleep 0.2`
|
||||
- The helper is used in 6 cmd tests
|
||||
|
||||
Implementation status:
|
||||
- Implemented by deleting the fixed `sleep 0.2` from `write_gated_workflow()` in `lib/crates/fabro-cli/tests/it/cmd/support.rs`
|
||||
- Implemented by deleting the fixed `sleep 0.2` from `write_gated_workflow()` in `lib/apps/fabro-cli/tests/it/cmd/support.rs`
|
||||
- Verified with `ulimit -n 4096; cargo nextest run -p fabro-cli -E 'test(attach_before_completion_streams_to_finished_state) | test(ctrl_c_cancels_active_run_via_server) | test(rm_force_terminates_active_run_worker) | test(start_rejects_already_active_or_completed_run) | test(start_runs_under_server_ownership_without_launcher_record)' --status-level fail --final-status-level fail --show-progress none`
|
||||
- Verification result: `5 passed`
|
||||
- Targeted 5-pass benchmark with `ulimit -n 4096` over the 5 tests that currently use the helper:
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ This is the right place for:
|
|||
|
||||
If the setup requires direct writes to internal run files or runtime directories, prefer this layer over `fabro-cli/tests/it`.
|
||||
|
||||
### `lib/crates/fabro-cli/tests/it/cmd/*.rs`
|
||||
### `lib/apps/fabro-cli/tests/it/cmd/*.rs`
|
||||
|
||||
`cmd/*` tests are command-owned tests.
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ Bad command-test assertions:
|
|||
- behavior primarily owned by another command
|
||||
- runtime internals that only exist because the test planted them by hand
|
||||
|
||||
### `lib/crates/fabro-cli/tests/it/workflow/*.rs`
|
||||
### `lib/apps/fabro-cli/tests/it/workflow/*.rs`
|
||||
|
||||
`workflow/*` tests are black-box workflow-behavior tests.
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ Examples:
|
|||
|
||||
These tests should focus on the workflow's observed behavior, not on CLI help text or command argument validation.
|
||||
|
||||
### `lib/crates/fabro-cli/tests/it/scenario/*.rs`
|
||||
### `lib/apps/fabro-cli/tests/it/scenario/*.rs`
|
||||
|
||||
`scenario/*` tests are cross-command lifecycle tests.
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ JSON objects without recognized fields are ignored.
|
|||
|
||||
### Validated routing output
|
||||
|
||||
Set `output_schema="routing"` on an agent or prompt node to require Fabro's built-in routing directive schema:
|
||||
Set `output_schema="routing"` on an agent, prompt, or command node to require Fabro's built-in routing directive schema:
|
||||
|
||||
```dot
|
||||
review [
|
||||
|
|
@ -81,7 +81,9 @@ With `output_schema="routing"`, the routing JSON must be an object with at least
|
|||
|
||||
Validated routing uses the same reverse scan as normal routing extraction: Fabro validates the last parsable JSON object that contains a recognized routing field. If a routing object is present but malformed or has invalid field types, Fabro repairs that response instead of falling through to a file fallback.
|
||||
|
||||
Fabro repairs invalid structured output inside the same LLM context before failing the node. For prompt nodes, Fabro appends the invalid assistant response and a corrective user message to the same message list. For agent nodes using the API backend, Fabro sends the corrective message to the same live agent session. `output_retries` controls these repair turns and defaults to `2`; `output_retries=0` validates once and fails without a repair turn. Negative values are treated as `0`. These repair turns are separate from workflow `max_retries` and do not consume node retry attempts.
|
||||
Fabro repairs invalid structured output inside the same LLM context before failing an agent or prompt node. For prompt nodes, Fabro appends the invalid assistant response and a corrective user message to the same message list. For agent nodes using the API backend, Fabro sends the corrective message to the same live agent session. `output_retries` controls these repair turns and defaults to `2`; `output_retries=0` validates once and fails without a repair turn. Negative values are treated as `0`. These repair turns are separate from workflow `max_retries` and do not consume node retry attempts.
|
||||
|
||||
Command nodes instead validate only after an exit-code-`0` script, applying the same reverse scan to merged stdout and stderr. Print the intended JSON object last. Invalid output fails deterministically without a repair turn, command retry, or `status.json` fallback; `output_retries`, `retry_policy`, and `max_retries` do not retry the validation failure. Nonzero exits keep their normal command failure behavior without schema validation.
|
||||
|
||||
### Routing fallback sources
|
||||
|
||||
|
|
@ -97,7 +99,7 @@ This fallback chain applies to normal routing extraction and to `output_schema="
|
|||
|
||||
The last-file fallback only reads `.json` and `.md` files (case-insensitive), and the routing JSON must be the final JSON object in the file, with only whitespace after it. Fabro ignores other file types and routing JSON followed by any other content. These restrictions do not apply to the dedicated `status.json` fallback.
|
||||
|
||||
Prompt nodes do not use file fallbacks; they validate or extract routing directives from the response text only.
|
||||
Prompt nodes do not use file fallbacks; they validate or extract routing directives from the response text only. Command nodes likewise have no file fallback and validate only their merged stdout and stderr.
|
||||
|
||||
If no source provides routing directives, the transition falls through to condition matching, unconditional edges, or weight-based tiebreaking as described in [Transitions](/workflows/transitions).
|
||||
|
||||
|
|
@ -121,7 +123,7 @@ review -> approve [label="Approve"]
|
|||
|
||||
## Custom structured outputs
|
||||
|
||||
Agent and prompt nodes can also validate their final JSON object against a JSON Schema file:
|
||||
Agent, prompt, and command nodes can also validate their final JSON object against a JSON Schema file:
|
||||
|
||||
```dot
|
||||
audit [
|
||||
|
|
@ -132,9 +134,9 @@ audit [
|
|||
]
|
||||
```
|
||||
|
||||
`output_schema="@path/to/schema.json"` uses the same workflow file-reference rules as prompt files: the schema is loaded relative to the workflow file and inlined before execution. The final JSON object in the LLM response is validated with `jsonschema`.
|
||||
`output_schema="@path/to/schema.json"` uses the same workflow file-reference rules as prompt files: the schema is loaded relative to the workflow file and inlined before execution. The final JSON object in the LLM response, or in a successful command's merged stdout and stderr, is validated with `jsonschema`.
|
||||
|
||||
Custom schema validation only reads the response text. It does not fall back to `status.json` or the last file touched by the agent.
|
||||
Custom schema validation only reads response or command output text. It does not fall back to `status.json` or the last file touched by the agent.
|
||||
|
||||
When custom schema validation succeeds, Fabro stores the parsed JSON value in context at:
|
||||
|
||||
|
|
@ -142,12 +144,12 @@ When custom schema validation succeeds, Fabro stores the parsed JSON value in co
|
|||
|---|---|
|
||||
| `output.{node_id}` | The parsed JSON object that matched the custom schema |
|
||||
|
||||
For example, node `audit` writes its parsed custom output to `output.audit`. Fabro still stores the raw response text at `response.audit`.
|
||||
For example, node `audit` writes its parsed custom output to `output.audit`. Fabro still stores raw LLM response text at `response.audit`; command output remains available through `command.output`.
|
||||
|
||||
If custom schema validation fails, Fabro sends concise validation feedback to the same prompt conversation or agent session and asks for corrected JSON. After `output_retries` repair turns are exhausted, the node fails terminally with `output schema validation failed after N repair attempt(s)`.
|
||||
If custom schema validation fails for an agent or prompt node, Fabro sends concise validation feedback to the same prompt conversation or agent session and asks for corrected JSON. After `output_retries` repair turns are exhausted, the node fails terminally with `output schema validation failed after N repair attempt(s)`. A command node instead fails deterministically after its first validation, without a repair turn or command retry.
|
||||
|
||||
<Note>
|
||||
Structured output validation currently applies to agent and prompt nodes. `backend="acp"` does not support `output_schema` in this release. Custom schemas update `output.{node_id}`; routing schemas update routing fields and `context_updates` instead.
|
||||
Structured output validation applies to agent, prompt, and command nodes. `backend="acp"` does not support `output_schema` in this release. Custom schemas update `output.{node_id}`; routing schemas update routing fields and merge `context_updates` as flat context keys that edge conditions can read. Edge conditions cannot traverse the custom `output.{node_id}` object.
|
||||
</Note>
|
||||
|
||||
## Output logging
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ The `fabro-api` crate generates Rust structs, enums, and a `reqwest`-based HTTP
|
|||
A `build.rs` script reads `docs/public/api-reference/fabro-api.yaml`, patches it from OpenAPI 3.1 to 3.0 for progenitor compatibility, and generates both types and a client. The generated code is written to `OUT_DIR` and included via:
|
||||
|
||||
```rust
|
||||
// lib/crates/fabro-api/src/lib.rs
|
||||
// lib/foundation/fabro-api/src/lib.rs
|
||||
include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ Use Claude Code's plan mode to collaborate on an implementation plan. Go back an
|
|||
> /plan Add retry logic to the webhook delivery system
|
||||
|
||||
Planning...
|
||||
1. Add RetryPolicy struct to lib/crates/fabro-webhooks/src/policy.rs
|
||||
1. Add RetryPolicy struct to lib/components/fabro-webhooks/src/policy.rs
|
||||
2. Implement exponential backoff with jitter
|
||||
3. Add max_retries field to WebhookConfig
|
||||
4. Write tests for retry timing, max attempts, and jitter bounds
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ Start nodes can also be identified by ID (`start` or `Start`). Exit nodes can be
|
|||
| `model` | String | Explicit model ID (overrides stylesheet) |
|
||||
| `provider` | String | Explicit provider name (overrides stylesheet). Auto-inferred from the model catalog when omitted. |
|
||||
| `project_memory` | Boolean | When `true` (default), prompt nodes discover and include project docs (`AGENTS.md`, `CLAUDE.md`, etc.) as a system prompt. Set to `false` to disable. |
|
||||
| `output_schema` | String | Optional structured output validation. Use `routing` for Fabro's built-in routing directive schema, `@path/to/schema.json` for a JSON Schema file, or an inline JSON Schema object string. Supported on agent and prompt nodes. |
|
||||
| `output_schema` | String | Optional structured output validation. Use `routing` for Fabro's built-in routing directive schema, `@path/to/schema.json` for a JSON Schema file, or an inline JSON Schema object string. Supported on agent, prompt, and command nodes. |
|
||||
| `output_retries` | Integer | Corrective structured-output turns inside the same prompt conversation or agent session. Default `2`; `0` validates once and fails without repair; negative values are treated as `0`. Separate from `max_retries`. |
|
||||
| `backend` | String | Agent execution backend: `api` (default) or `acp`. `api` runs Fabro's tool loop through provider APIs; `acp` runs an Agent Client Protocol stdio agent inside the active sandbox. Prompt nodes are API-only. See [Agents — Backends](/core-concepts/agents#backends). |
|
||||
| `acp.command` | String | Shell command for nodes with `backend="acp"`. Mutually exclusive with `acp.config`. The value is always parsed as a command string, not JSON. |
|
||||
|
|
@ -214,7 +214,7 @@ Start nodes can also be identified by ID (`start` or `Start`). Exit nodes can be
|
|||
|
||||
#### Structured output validation
|
||||
|
||||
`output_schema` opts an agent or prompt node into strict JSON validation:
|
||||
`output_schema` opts an agent, prompt, or command node into strict JSON validation:
|
||||
|
||||
```dot
|
||||
review [
|
||||
|
|
@ -236,6 +236,8 @@ audit [
|
|||
- `output_retries` defaults to `2` and controls only these corrective structured-output turns. Negative values are treated as `0`. It is not the same as `max_retries` and does not consume workflow retry attempts.
|
||||
- Custom schema output is stored in context at `output.{node_id}`. Routing schema output updates routing fields and any `context_updates`.
|
||||
- Agent routing fallbacks still apply to `output_schema="routing"`: response text first, then `status.json`, then the last file touched by the agent. The last-file fallback only accepts `.json` and `.md` files (case-insensitive) whose final JSON object contains the routing directive; only whitespace may follow it. Custom schemas and prompt nodes validate response text only.
|
||||
- Command nodes validate merged stdout and stderr only after the script exits with code `0`, using the same object selection as agents and prompts: custom schemas validate the last JSON object, and `routing` validates the last JSON object containing a recognized routing field. Print the intended JSON object last. A validation error is a deterministic, non-retryable failure with no repair turn or `status.json` fallback. `output_retries`, `retry_policy`, and `max_retries` do not retry it. Nonzero exits retain normal command failure behavior without schema validation.
|
||||
- For commands, custom schema output is stored at `output.{node_id}`; edge conditions cannot traverse into its fields. The `routing` schema applies routing fields and merges `context_updates` into flat context keys, which conditions can read (for example, `context.kept_count`).
|
||||
- `backend="acp"` with `output_schema` is unsupported in this release.
|
||||
|
||||
### Command nodes
|
||||
|
|
@ -244,6 +246,7 @@ audit [
|
|||
|---|---|---|
|
||||
| `script` | String | Shell command to execute |
|
||||
| `language` | String | `"shell"` (default) or `"python"` |
|
||||
| `output_schema` | String | Optional structured output validation. Accepts `routing`, `@path/to/schema.json`, or an inline JSON Schema object string. See [Structured output validation](#structured-output-validation). |
|
||||
|
||||
### Parallel (fan-out) nodes
|
||||
|
||||
|
|
|
|||
|
|
@ -18,40 +18,40 @@ sleep_inhibitor = ["dep:core-foundation"]
|
|||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
fabro-auth = { path = "../fabro-auth" }
|
||||
fabro-config = { path = "../fabro-config" }
|
||||
fabro-environment = { path = "../fabro-environment" }
|
||||
fabro-llm = { path = "../fabro-llm" }
|
||||
fabro-model = { path = "../fabro-model" }
|
||||
fabro-oauth = { path = "../fabro-oauth" }
|
||||
fabro-github = { path = "../fabro-github" }
|
||||
fabro-agent = { path = "../fabro-agent" }
|
||||
fabro-dump = { path = "../fabro-dump" }
|
||||
fabro-hooks = { path = "../fabro-hooks" }
|
||||
fabro-install = { path = "../fabro-install" }
|
||||
fabro-interview = { path = "../fabro-interview" }
|
||||
fabro-mcp = { path = "../fabro-mcp" }
|
||||
fabro-auth = { path = "../../foundation/fabro-auth" }
|
||||
fabro-config = { path = "../../foundation/fabro-config" }
|
||||
fabro-environment = { path = "../../components/fabro-environment" }
|
||||
fabro-llm = { path = "../../components/fabro-llm" }
|
||||
fabro-model = { path = "../../foundation/fabro-model" }
|
||||
fabro-oauth = { path = "../../foundation/fabro-oauth" }
|
||||
fabro-github = { path = "../../components/fabro-github" }
|
||||
fabro-agent = { path = "../../components/fabro-agent" }
|
||||
fabro-dump = { path = "../../components/fabro-dump" }
|
||||
fabro-hooks = { path = "../../components/fabro-hooks" }
|
||||
fabro-install = { path = "../../components/fabro-install" }
|
||||
fabro-interview = { path = "../../components/fabro-interview" }
|
||||
fabro-mcp = { path = "../../components/fabro-mcp" }
|
||||
fabro-mcp-server = { path = "../fabro-mcp-server" }
|
||||
fabro-manifest = { path = "../fabro-manifest" }
|
||||
fabro-proc = { path = "../fabro-proc" }
|
||||
fabro-sandbox = { path = "../fabro-sandbox", features = ["daytona"] }
|
||||
fabro-checkpoint = { path = "../fabro-checkpoint" }
|
||||
fabro-graphviz = { path = "../fabro-graphviz" }
|
||||
fabro-validate = { path = "../fabro-validate" }
|
||||
fabro-workflow = { path = "../fabro-workflow" }
|
||||
fabro-manifest = { path = "../../components/fabro-manifest" }
|
||||
fabro-proc = { path = "../../foundation/fabro-proc" }
|
||||
fabro-sandbox = { path = "../../components/fabro-sandbox", features = ["daytona"] }
|
||||
fabro-checkpoint = { path = "../../components/fabro-checkpoint" }
|
||||
fabro-graphviz = { path = "../../components/fabro-graphviz" }
|
||||
fabro-validate = { path = "../../components/fabro-validate" }
|
||||
fabro-workflow = { path = "../../components/fabro-workflow" }
|
||||
fabro-server = { path = "../fabro-server" }
|
||||
fabro-client = { path = "../fabro-client" }
|
||||
fabro-api = { path = "../fabro-api" }
|
||||
fabro-telemetry = { path = "../fabro-telemetry" }
|
||||
fabro-store = { path = "../fabro-store" }
|
||||
fabro-vault = { path = "../fabro-vault" }
|
||||
fabro-types = { path = "../fabro-types", features = ["clap"] }
|
||||
fabro-client = { path = "../../foundation/fabro-client" }
|
||||
fabro-api = { path = "../../foundation/fabro-api" }
|
||||
fabro-telemetry = { path = "../../foundation/fabro-telemetry" }
|
||||
fabro-store = { path = "../../components/fabro-store" }
|
||||
fabro-vault = { path = "../../foundation/fabro-vault" }
|
||||
fabro-types = { path = "../../foundation/fabro-types", features = ["clap"] }
|
||||
fabro-redact.workspace = true
|
||||
fabro-util = { path = "../fabro-util" }
|
||||
fabro-util = { path = "../../foundation/fabro-util" }
|
||||
fabro-http.workspace = true
|
||||
fabro-static.workspace = true
|
||||
fabro-template = { path = "../fabro-template" }
|
||||
fabro-tool = { path = "../fabro-tool" }
|
||||
fabro-template = { path = "../../foundation/fabro-template" }
|
||||
fabro-tool = { path = "../../components/fabro-tool" }
|
||||
clap.workspace = true
|
||||
clap_complete.workspace = true
|
||||
cli-table.workspace = true
|
||||
|
|
@ -111,16 +111,16 @@ core-foundation = { version = "0.9", optional = true }
|
|||
openssl = { version = "0.10", features = ["vendored"] }
|
||||
|
||||
[build-dependencies]
|
||||
fabro-build-support = { path = "../build-support" }
|
||||
fabro-build-support = { path = "../../foundation/build-support" }
|
||||
chrono = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "2"
|
||||
fabro-acp = { path = "../fabro-acp", features = ["test-support"] }
|
||||
fabro-build-support = { path = "../build-support" }
|
||||
fabro-acp = { path = "../../components/fabro-acp", features = ["test-support"] }
|
||||
fabro-build-support = { path = "../../foundation/build-support" }
|
||||
fabro-server = { path = "../fabro-server", features = ["test-support"] }
|
||||
fabro-workflow = { path = "../fabro-workflow", features = ["test-support"] }
|
||||
fabro-types = { path = "../fabro-types", features = ["clap", "test-support"] }
|
||||
fabro-workflow = { path = "../../components/fabro-workflow", features = ["test-support"] }
|
||||
fabro-types = { path = "../../foundation/fabro-types", features = ["clap", "test-support"] }
|
||||
insta = { workspace = true, features = ["filters"] }
|
||||
paste = "1"
|
||||
predicates = "3"
|
||||
|
|
@ -129,7 +129,7 @@ tempfile = "3"
|
|||
temp-env = "0.3"
|
||||
httpmock = "0.8"
|
||||
fabro-test = { workspace = true }
|
||||
fabro-macros = { path = "../fabro-macros" }
|
||||
fabro-macros = { path = "../../foundation/fabro-macros" }
|
||||
hkdf.workspace = true
|
||||
reqwest = { workspace = true, features = ["cookies"] }
|
||||
tokio = { workspace = true, features = ["test-util", "macros"] }
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue