refactor: move server startup CLI to wf_server
This commit is contained in:
@@ -81,11 +81,9 @@ auth admin are implemented. The next work is polish, not new broad surfaces.
|
|||||||
- New source families should follow the generic runtime source lifecycle rather
|
- New source families should follow the generic runtime source lifecycle rather
|
||||||
than being forced through MCP `ConnectionConfig`:
|
than being forced through MCP `ConnectionConfig`:
|
||||||
[`runtime source lifecycle`](superpowers/specs/2026-06-09-runtime-source-lifecycle.md).
|
[`runtime source lifecycle`](superpowers/specs/2026-06-09-runtime-source-lifecycle.md).
|
||||||
- Server startup policy should move out of the JSON-RPC transport package and
|
- Completed: server startup policy moved to `wf_server.cli`; JSON-RPC HTTP
|
||||||
into `wf_server` before adding more hosted transports:
|
remains in `wf_transport_rpc_http`:
|
||||||
[`server CLI and transport boundary`](superpowers/specs/2026-06-10-server-cli-transport-boundary.md).
|
[`server CLI and transport boundary`](superpowers/specs/2026-06-10-server-cli-transport-boundary.md).
|
||||||
Active implementation plan:
|
|
||||||
[`server CLI ownership move`](superpowers/plans/2026-06-10-server-cli-ownership-move.md).
|
|
||||||
- Deferred auth work: OAuth/OIDC, production secret manager integration,
|
- Deferred auth work: OAuth/OIDC, production secret manager integration,
|
||||||
encrypted-at-rest file format, and provider-specific display models.
|
encrypted-at-rest file format, and provider-specific display models.
|
||||||
- Active specs:
|
- Active specs:
|
||||||
|
|||||||
+4
-5
@@ -11,8 +11,8 @@ paths should go through `wf_server` plus transport/source packages.
|
|||||||
| `wf_core` | Deterministic workflow kernel: models, validation, runtime, run state, traces, interrupts, foreach, and path/state operations. | Runtime users, `wf_authoring`, workflow adapters. |
|
| `wf_core` | Deterministic workflow kernel: models, validation, runtime, run state, traces, interrupts, foreach, and path/state operations. | Runtime users, `wf_authoring`, workflow adapters. |
|
||||||
| `wf_authoring` | Ergonomic workflow construction: `@node`, `NodeSpec`, builder DSL, conditions, path helpers, reusable ops, subgraph nodes. | Humans, tests, future LLM workflow builders. |
|
| `wf_authoring` | Ergonomic workflow construction: `@node`, `NodeSpec`, builder DSL, conditions, path helpers, reusable ops, subgraph nodes. | Humans, tests, future LLM workflow builders. |
|
||||||
| `wf_api` | Workflow application surface over core/artifacts/platform: capabilities, drafts, artifacts, deployments, runs, and source/admin surfaces. | `wf_cli`, `wf_server`, JSON-RPC clients, future transports. |
|
| `wf_api` | Workflow application surface over core/artifacts/platform: capabilities, drafts, artifacts, deployments, runs, and source/admin surfaces. | `wf_cli`, `wf_server`, JSON-RPC clients, future transports. |
|
||||||
| `wf_server` | Durable server composition boundary around `WorkflowApi` plus optional admin/source-registry surfaces. Target home for server startup CLI/policy. | Transport packages and server startup code. |
|
| `wf_server` | Durable server composition boundary around `WorkflowApi` plus optional admin/source-registry surfaces. Owns the `wf-rpc-server` startup CLI/policy. | Transport packages and server startup code. |
|
||||||
| `wf_transport_rpc_http` | JSON-RPC-over-HTTP app/client. The current `wf-rpc-server` CLI is slated to move to `wf_server` with a compatibility shim. | Remote `wf` clients and local server smoke tests. |
|
| `wf_transport_rpc_http` | JSON-RPC-over-HTTP app/client and compatibility CLI shim. | Remote `wf` clients and local server smoke tests. |
|
||||||
| `wf_sources_mcp` | MCP-as-upstream-source implementation: ids, registry DTOs, auth/catalog stores, discovery, SDK client/facade, runtime pool, wrappers. | `wf_server`, broker glue, MCP source tests. |
|
| `wf_sources_mcp` | MCP-as-upstream-source implementation: ids, registry DTOs, auth/catalog stores, discovery, SDK client/facade, runtime pool, wrappers. | `wf_server`, broker glue, MCP source tests. |
|
||||||
| `wf_mcp` | MCP frontend/compatibility package: legacy `wf-mcp` entrypoints, broker glue, proxy/admin tools, and shims while extraction continues. | Compatibility callers and MCP transport work. |
|
| `wf_mcp` | MCP frontend/compatibility package: legacy `wf-mcp` entrypoints, broker glue, proxy/admin tools, and shims while extraction continues. | Compatibility callers and MCP transport work. |
|
||||||
| `wf_cli` | Command-line frontend over local or remote workflow APIs. | Humans, scripts, agent skills. |
|
| `wf_cli` | Command-line frontend over local or remote workflow APIs. | Humans, scripts, agent skills. |
|
||||||
@@ -39,9 +39,8 @@ paths should go through `wf_server` plus transport/source packages.
|
|||||||
upstream tools/resources/prompts.
|
upstream tools/resources/prompts.
|
||||||
- `wf_mcp`: MCP-specific frontend and compatibility package.
|
- `wf_mcp`: MCP-specific frontend and compatibility package.
|
||||||
- `wf-mcp`: legacy/special-purpose MCP script from `pyproject.toml`.
|
- `wf-mcp`: legacy/special-purpose MCP script from `pyproject.toml`.
|
||||||
- `wf-rpc-server`: preferred durable workflow server script for CLI/API clients;
|
- `wf-rpc-server`: preferred durable workflow server script for CLI/API clients,
|
||||||
currently implemented in `wf_transport_rpc_http.cli`, but the target owner is
|
implemented by `wf_server.cli`.
|
||||||
`wf_server.cli`.
|
|
||||||
- `wf_mcp.broker.WfMcpService.get_catalog()`: backend MCP catalog snapshots.
|
- `wf_mcp.broker.WfMcpService.get_catalog()`: backend MCP catalog snapshots.
|
||||||
- `wf_mcp.broker.WfMcpService.get_planner_catalog()`: backend snapshots plus
|
- `wf_mcp.broker.WfMcpService.get_planner_catalog()`: backend snapshots plus
|
||||||
broker-local workflow sources such as `wf.std` and `wf.mcp`.
|
broker-local workflow sources such as `wf.std` and `wf.mcp`.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Date: 2026-06-10
|
Date: 2026-06-10
|
||||||
|
|
||||||
Status: design direction; implementation not started
|
Status: first move slice implemented
|
||||||
|
|
||||||
Related:
|
Related:
|
||||||
|
|
||||||
@@ -90,6 +90,16 @@ wf-rpc-server = "wf_server.cli:main"
|
|||||||
Keep `wf_transport_rpc_http.cli` temporarily so tests and imports do not break
|
Keep `wf_transport_rpc_http.cli` temporarily so tests and imports do not break
|
||||||
immediately.
|
immediately.
|
||||||
|
|
||||||
|
## Implementation Status
|
||||||
|
|
||||||
|
First move slice complete:
|
||||||
|
|
||||||
|
- `wf-rpc-server` script entrypoint points at `wf_server.cli:main`.
|
||||||
|
- `wf_server.cli` owns startup config parsing and server composition.
|
||||||
|
- `wf_transport_rpc_http.cli` remains as a compatibility shim.
|
||||||
|
- `wf_transport_rpc_http.create_rpc_app(server)` remains the JSON-RPC HTTP
|
||||||
|
transport adapter.
|
||||||
|
|
||||||
## Why Not Move `create_rpc_app`
|
## Why Not Move `create_rpc_app`
|
||||||
|
|
||||||
`create_rpc_app(server)` is transport code:
|
`create_rpc_app(server)` is transport code:
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ dependencies = [
|
|||||||
[project.scripts]
|
[project.scripts]
|
||||||
wf = "wf_cli.app:main"
|
wf = "wf_cli.app:main"
|
||||||
wf-mcp = "wf_mcp.cli:main"
|
wf-mcp = "wf_mcp.cli:main"
|
||||||
wf-rpc-server = "wf_transport_rpc_http.cli:main"
|
wf-rpc-server = "wf_server.cli:main"
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import typer
|
||||||
|
import uvicorn
|
||||||
|
|
||||||
|
from wf_config import (
|
||||||
|
FilesystemStoreConfig,
|
||||||
|
RpcHttpTransportConfig,
|
||||||
|
load_workflow_config,
|
||||||
|
)
|
||||||
|
from wf_server.config import (
|
||||||
|
build_workflow_server_from_legacy_mcp_config,
|
||||||
|
build_workflow_server_from_workflow_config,
|
||||||
|
)
|
||||||
|
from wf_server.context import build_local_static_workflow_server
|
||||||
|
from wf_transport_rpc_http import create_rpc_app
|
||||||
|
|
||||||
|
app = typer.Typer(add_completion=False)
|
||||||
|
|
||||||
|
|
||||||
|
@app.callback(invoke_without_command=True)
|
||||||
|
def serve(
|
||||||
|
config: Path | None = typer.Option(
|
||||||
|
None,
|
||||||
|
"--config",
|
||||||
|
help="Path to neutral workflow config JSON.",
|
||||||
|
),
|
||||||
|
store_root: Path | None = typer.Option(
|
||||||
|
None,
|
||||||
|
"--store-root",
|
||||||
|
help="Override filesystem workflow store root.",
|
||||||
|
),
|
||||||
|
mcp_config: Path | None = typer.Option(
|
||||||
|
None,
|
||||||
|
"--mcp-config",
|
||||||
|
help="Path to MCP broker config JSON for MCP-backed workflow server.",
|
||||||
|
),
|
||||||
|
host: str | None = typer.Option(
|
||||||
|
None,
|
||||||
|
"--host",
|
||||||
|
help="Override RPC bind host; defaults to config or 127.0.0.1.",
|
||||||
|
),
|
||||||
|
port: int | None = typer.Option(
|
||||||
|
None,
|
||||||
|
"--port",
|
||||||
|
min=1,
|
||||||
|
max=65535,
|
||||||
|
help="Override RPC bind port; defaults to config or 8765.",
|
||||||
|
),
|
||||||
|
) -> None:
|
||||||
|
"""Serve WorkflowApi over JSON-RPC HTTP."""
|
||||||
|
if mcp_config is not None and store_root is not None:
|
||||||
|
raise typer.BadParameter("--mcp-config cannot be combined with --store-root")
|
||||||
|
|
||||||
|
resolved_store_root = store_root
|
||||||
|
resolved_host = host
|
||||||
|
resolved_port = port
|
||||||
|
resolved_rpc_path = "/rpc"
|
||||||
|
|
||||||
|
server = None
|
||||||
|
if mcp_config is not None:
|
||||||
|
server = build_workflow_server_from_legacy_mcp_config(mcp_config)
|
||||||
|
|
||||||
|
if config is not None:
|
||||||
|
workflow_config = load_workflow_config(config)
|
||||||
|
store = workflow_config.server.workflow_store
|
||||||
|
if server is None and store_root is None:
|
||||||
|
server = build_workflow_server_from_workflow_config(workflow_config)
|
||||||
|
elif server is None:
|
||||||
|
has_mcp_sources = any(
|
||||||
|
getattr(source, "kind", None) == "mcp"
|
||||||
|
for source in workflow_config.server.sources
|
||||||
|
)
|
||||||
|
if has_mcp_sources:
|
||||||
|
raise typer.BadParameter(
|
||||||
|
"--store-root cannot override MCP-source config"
|
||||||
|
)
|
||||||
|
if not isinstance(store, FilesystemStoreConfig):
|
||||||
|
raise typer.BadParameter(
|
||||||
|
"wf-rpc-server currently requires filesystem store"
|
||||||
|
)
|
||||||
|
resolved_store_root = resolved_store_root or store.root
|
||||||
|
rpc_transport = next(
|
||||||
|
(
|
||||||
|
transport
|
||||||
|
for transport in workflow_config.server.transports
|
||||||
|
if isinstance(transport, RpcHttpTransportConfig)
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
if rpc_transport is not None:
|
||||||
|
resolved_host = host or rpc_transport.host
|
||||||
|
resolved_port = port or rpc_transport.port
|
||||||
|
resolved_rpc_path = rpc_transport.path
|
||||||
|
|
||||||
|
if server is None:
|
||||||
|
if resolved_store_root is None:
|
||||||
|
raise typer.BadParameter(
|
||||||
|
"--store-root is required when --config is not supplied"
|
||||||
|
)
|
||||||
|
server = build_local_static_workflow_server(resolved_store_root)
|
||||||
|
|
||||||
|
rpc_app = create_rpc_app(server, rpc_path=resolved_rpc_path)
|
||||||
|
uvicorn.run(
|
||||||
|
rpc_app,
|
||||||
|
host=resolved_host or "127.0.0.1",
|
||||||
|
port=resolved_port or 8765,
|
||||||
|
access_log=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app()
|
||||||
@@ -1,116 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from pathlib import Path
|
from wf_server.cli import app, main
|
||||||
|
|
||||||
import typer
|
__all__ = ["app", "main"]
|
||||||
import uvicorn
|
|
||||||
|
|
||||||
from wf_config import (
|
|
||||||
FilesystemStoreConfig,
|
|
||||||
RpcHttpTransportConfig,
|
|
||||||
load_workflow_config,
|
|
||||||
)
|
|
||||||
from wf_server.config import (
|
|
||||||
build_workflow_server_from_legacy_mcp_config,
|
|
||||||
build_workflow_server_from_workflow_config,
|
|
||||||
)
|
|
||||||
from wf_server.context import build_local_static_workflow_server
|
|
||||||
|
|
||||||
from .app import create_rpc_app
|
|
||||||
|
|
||||||
app = typer.Typer(add_completion=False)
|
|
||||||
|
|
||||||
|
|
||||||
@app.callback(invoke_without_command=True)
|
|
||||||
def serve(
|
|
||||||
config: Path | None = typer.Option(
|
|
||||||
None,
|
|
||||||
"--config",
|
|
||||||
help="Path to neutral workflow config JSON.",
|
|
||||||
),
|
|
||||||
store_root: Path | None = typer.Option(
|
|
||||||
None,
|
|
||||||
"--store-root",
|
|
||||||
help="Override filesystem workflow store root.",
|
|
||||||
),
|
|
||||||
mcp_config: Path | None = typer.Option(
|
|
||||||
None,
|
|
||||||
"--mcp-config",
|
|
||||||
help="Path to MCP broker config JSON for MCP-backed workflow server.",
|
|
||||||
),
|
|
||||||
host: str | None = typer.Option(
|
|
||||||
None,
|
|
||||||
"--host",
|
|
||||||
help="Override RPC bind host; defaults to config or 127.0.0.1.",
|
|
||||||
),
|
|
||||||
port: int | None = typer.Option(
|
|
||||||
None,
|
|
||||||
"--port",
|
|
||||||
min=1,
|
|
||||||
max=65535,
|
|
||||||
help="Override RPC bind port; defaults to config or 8765.",
|
|
||||||
),
|
|
||||||
) -> None:
|
|
||||||
"""Serve WorkflowApi over JSON-RPC HTTP."""
|
|
||||||
if mcp_config is not None and store_root is not None:
|
|
||||||
raise typer.BadParameter("--mcp-config cannot be combined with --store-root")
|
|
||||||
|
|
||||||
resolved_store_root = store_root
|
|
||||||
resolved_host = host
|
|
||||||
resolved_port = port
|
|
||||||
resolved_rpc_path = "/rpc"
|
|
||||||
|
|
||||||
server = None
|
|
||||||
if mcp_config is not None:
|
|
||||||
server = build_workflow_server_from_legacy_mcp_config(mcp_config)
|
|
||||||
|
|
||||||
if config is not None:
|
|
||||||
workflow_config = load_workflow_config(config)
|
|
||||||
store = workflow_config.server.workflow_store
|
|
||||||
if server is None and store_root is None:
|
|
||||||
server = build_workflow_server_from_workflow_config(workflow_config)
|
|
||||||
elif server is None:
|
|
||||||
has_mcp_sources = any(
|
|
||||||
getattr(source, "kind", None) == "mcp"
|
|
||||||
for source in workflow_config.server.sources
|
|
||||||
)
|
|
||||||
if has_mcp_sources:
|
|
||||||
raise typer.BadParameter(
|
|
||||||
"--store-root cannot override MCP-source config"
|
|
||||||
)
|
|
||||||
if not isinstance(store, FilesystemStoreConfig):
|
|
||||||
raise typer.BadParameter(
|
|
||||||
"wf-rpc-server currently requires filesystem store"
|
|
||||||
)
|
|
||||||
resolved_store_root = resolved_store_root or store.root
|
|
||||||
rpc_transport = next(
|
|
||||||
(
|
|
||||||
transport
|
|
||||||
for transport in workflow_config.server.transports
|
|
||||||
if isinstance(transport, RpcHttpTransportConfig)
|
|
||||||
),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
if rpc_transport is not None:
|
|
||||||
resolved_host = host or rpc_transport.host
|
|
||||||
resolved_port = port or rpc_transport.port
|
|
||||||
resolved_rpc_path = rpc_transport.path
|
|
||||||
|
|
||||||
if server is None:
|
|
||||||
if resolved_store_root is None:
|
|
||||||
raise typer.BadParameter(
|
|
||||||
"--store-root is required when --config is not supplied"
|
|
||||||
)
|
|
||||||
server = build_local_static_workflow_server(resolved_store_root)
|
|
||||||
|
|
||||||
rpc_app = create_rpc_app(server, rpc_path=resolved_rpc_path)
|
|
||||||
uvicorn.run(
|
|
||||||
rpc_app,
|
|
||||||
host=resolved_host or "127.0.0.1",
|
|
||||||
port=resolved_port or 8765,
|
|
||||||
access_log=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
app()
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import json
|
|||||||
|
|
||||||
from typer.testing import CliRunner
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
from wf_transport_rpc_http.cli import app
|
from wf_server.cli import app
|
||||||
|
|
||||||
|
|
||||||
def test_rpc_server_cli_help_mentions_store_root() -> None:
|
def test_rpc_server_cli_help_mentions_store_root() -> None:
|
||||||
@@ -86,11 +86,11 @@ def test_rpc_server_cli_uses_configured_store_and_transport(
|
|||||||
captured["access_log"] = access_log
|
captured["access_log"] = access_log
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"wf_transport_rpc_http.cli.build_workflow_server_from_workflow_config",
|
"wf_server.cli.build_workflow_server_from_workflow_config",
|
||||||
fake_build_server,
|
fake_build_server,
|
||||||
)
|
)
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.create_rpc_app", fake_create_rpc_app)
|
monkeypatch.setattr("wf_server.cli.create_rpc_app", fake_create_rpc_app)
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.uvicorn.run", fake_uvicorn_run)
|
monkeypatch.setattr("wf_server.cli.uvicorn.run", fake_uvicorn_run)
|
||||||
|
|
||||||
result = CliRunner().invoke(app, ["--config", str(config_path)])
|
result = CliRunner().invoke(app, ["--config", str(config_path)])
|
||||||
|
|
||||||
@@ -131,11 +131,11 @@ def test_rpc_server_cli_uses_mcp_config_server(monkeypatch, tmp_path) -> None:
|
|||||||
captured["access_log"] = access_log
|
captured["access_log"] = access_log
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"wf_transport_rpc_http.cli.build_workflow_server_from_legacy_mcp_config",
|
"wf_server.cli.build_workflow_server_from_legacy_mcp_config",
|
||||||
fake_build_mcp_server,
|
fake_build_mcp_server,
|
||||||
)
|
)
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.create_rpc_app", fake_create_rpc_app)
|
monkeypatch.setattr("wf_server.cli.create_rpc_app", fake_create_rpc_app)
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.uvicorn.run", fake_uvicorn_run)
|
monkeypatch.setattr("wf_server.cli.uvicorn.run", fake_uvicorn_run)
|
||||||
|
|
||||||
result = CliRunner().invoke(
|
result = CliRunner().invoke(
|
||||||
app,
|
app,
|
||||||
@@ -203,8 +203,8 @@ def test_rpc_server_cli_mcp_config_builds_registry_capable_server(
|
|||||||
captured["host"] = host
|
captured["host"] = host
|
||||||
captured["port"] = port
|
captured["port"] = port
|
||||||
|
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.create_rpc_app", fake_create_rpc_app)
|
monkeypatch.setattr("wf_server.cli.create_rpc_app", fake_create_rpc_app)
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.uvicorn.run", fake_uvicorn_run)
|
monkeypatch.setattr("wf_server.cli.uvicorn.run", fake_uvicorn_run)
|
||||||
|
|
||||||
result = CliRunner().invoke(app, ["--mcp-config", str(config_path)])
|
result = CliRunner().invoke(app, ["--mcp-config", str(config_path)])
|
||||||
|
|
||||||
@@ -260,8 +260,8 @@ def test_rpc_server_cli_mcp_config_with_config_uses_transport_settings(
|
|||||||
captured["port"] = port
|
captured["port"] = port
|
||||||
captured["access_log"] = access_log
|
captured["access_log"] = access_log
|
||||||
|
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.create_rpc_app", fake_create_rpc_app)
|
monkeypatch.setattr("wf_server.cli.create_rpc_app", fake_create_rpc_app)
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.uvicorn.run", fake_uvicorn_run)
|
monkeypatch.setattr("wf_server.cli.uvicorn.run", fake_uvicorn_run)
|
||||||
|
|
||||||
result = CliRunner().invoke(
|
result = CliRunner().invoke(
|
||||||
app,
|
app,
|
||||||
@@ -304,11 +304,11 @@ def test_rpc_server_cli_config_with_mcp_source_uses_mcp_builder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"wf_transport_rpc_http.cli.build_workflow_server_from_workflow_config",
|
"wf_server.cli.build_workflow_server_from_workflow_config",
|
||||||
fake_build_from_workflow_config,
|
fake_build_from_workflow_config,
|
||||||
)
|
)
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.create_rpc_app", fake_create_rpc_app)
|
monkeypatch.setattr("wf_server.cli.create_rpc_app", fake_create_rpc_app)
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.uvicorn.run", fake_run)
|
monkeypatch.setattr("wf_server.cli.uvicorn.run", fake_run)
|
||||||
|
|
||||||
config_path = tmp_path / "wf.json"
|
config_path = tmp_path / "wf.json"
|
||||||
config_path.write_text(
|
config_path.write_text(
|
||||||
@@ -333,10 +333,6 @@ def test_rpc_server_cli_config_with_mcp_source_uses_mcp_builder(
|
|||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
)
|
)
|
||||||
|
|
||||||
from typer.testing import CliRunner
|
|
||||||
|
|
||||||
from wf_transport_rpc_http.cli import app
|
|
||||||
|
|
||||||
result = CliRunner().invoke(app, ["--config", str(config_path)])
|
result = CliRunner().invoke(app, ["--config", str(config_path)])
|
||||||
|
|
||||||
assert result.exit_code == 0, result.output
|
assert result.exit_code == 0, result.output
|
||||||
@@ -413,11 +409,11 @@ def test_rpc_server_cli_config_uses_workflow_store_override(
|
|||||||
captured["app"] = app_obj
|
captured["app"] = app_obj
|
||||||
|
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"wf_transport_rpc_http.cli.build_workflow_server_from_workflow_config",
|
"wf_server.cli.build_workflow_server_from_workflow_config",
|
||||||
fake_build_server,
|
fake_build_server,
|
||||||
)
|
)
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.create_rpc_app", fake_create_rpc_app)
|
monkeypatch.setattr("wf_server.cli.create_rpc_app", fake_create_rpc_app)
|
||||||
monkeypatch.setattr("wf_transport_rpc_http.cli.uvicorn.run", fake_uvicorn_run)
|
monkeypatch.setattr("wf_server.cli.uvicorn.run", fake_uvicorn_run)
|
||||||
|
|
||||||
result = CliRunner().invoke(app, ["--config", str(config_path)])
|
result = CliRunner().invoke(app, ["--config", str(config_path)])
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
|
||||||
|
def test_rpc_server_cli_compat_import_matches_server_cli() -> None:
|
||||||
|
from wf_server import cli as server_cli
|
||||||
|
from wf_transport_rpc_http import cli as transport_cli
|
||||||
|
|
||||||
|
assert transport_cli.app is server_cli.app
|
||||||
|
assert transport_cli.main is server_cli.main
|
||||||
Reference in New Issue
Block a user