Architecture
pulse-cli speaks to an engine through a port. Each engine has its own adapter behind that port. Today every adapter passes straight through to the Camunda 7 REST API. When an engine diverges, only its adapter changes.
Layers
| Folder | What it holds |
|---|---|
src/engine-port | What pulse-cli needs from an engine: EnginePort and EngineAdapter. Types only |
src/engines | One adapter per engine: operaton, cibseven, camunda7 |
src/api | One folder per engine API. camunda7-rest builds catalog and port |
src/workflow | The workflow commands. They know the port, never an adapter or an API |
src/cli | Selects the adapter and registers its commands |
dependency-cruiser enforces the boundaries (pnpm lint:architecture && pnpm lint:architecture:cli):
workflowimportsengine-port, neverenginesorapi.- Only
engines/<name>/adapter.tsimportsapi. - Adapters do not import each other. An API does not import another API.
engine-portimports types only.api,engine-portandenginesuse no Node built-ins.- An adapter reads only its own catalog,
src/generated/catalog.<name>.json.
From spec to request
The commands are data. A generator turns the OpenAPI spec into one catalog per engine. The selected adapter hands its catalog to the CLI, which registers commands, help and describe from it and sends requests over HTTP.
Selecting the engine
run.ts picks the adapter before it registers a single command. Only then do commands, help and describe match the catalog of that engine.
A config file that cannot be read does not stop the selection: pulse-cli falls back to camunda7, and the command reports the problem when it reads its configuration.
A workflow command
The decisions behind this: Architecture decisions.