Port remaining CLI commands to libswamp + renderer pattern
Opened by swampadmin · 3/19/2026
The swamp CLI is being refactored to separate domain orchestration from presentation logic per design/libswamp.md and design/rendering.md. Every operation becomes an async function* generator in src/libswamp/ yielding typed events, consumed by mode-specific Renderer<E> classes via consumeStream().
3 commands are already ported: auth whoami, model method run, workflow run. ~55 commands remain with inline presentation logic in src/presentation/output/.
Top constraint: Output must not change (same log lines, same JSON shapes). Domain logic must not change. Commands migrate incrementally.
Architectural Decisions
Ink search commands become full Renderer<E> implementations with a distinct InkXxxRenderer (or TuiXxxRenderer) class — not a log renderer that happens to use Ink. The Ink renderer's async completed handler launches the interactive TUI and stores the user's selection. The renderer extends the base interface (e.g., selectedItem(): T | undefined), matching the existing WorkflowRunRenderer.workflowFailed() pattern. The factory selects the Ink renderer when in log mode (TTY). .tsx components move to src/presentation/renderers/.
Confirmation prompts (delete, gc, overwrite) live in the CLI layer before calling the generator. Complex "what will be affected" info uses a two-phase pattern: preview generator (read-only) -> CLI prompt -> execute generator.
Editor launch is injected via deps.openEditor(path), making generators testable.
Auth login browser flow modeled as a generator with I/O injected through deps.
Per-Command Migration Checklist
For every command:
- Define event type union (
kinddiscriminant,completed+errorterminals) - Define
XxxDepsinterface +createXxxDeps()factory - Implement
async function*generator (zero presentation logic,ctx.loggerdebug/trace only) - Implement
LogXxxRenderer+JsonXxxRenderer(+InkXxxRendererfor search commands). Verify output parity. - Update CLI handler to pure orchestration: wire deps, create renderer,
consumeStream() - Export from
src/libswamp/mod.ts, delete oldsrc/presentation/output/xxx_output.ts - Generator unit tests with fake deps; existing tests pass unchanged
Batches
Batch 0: Infrastructure Prep
Add shared error factories to
src/libswamp/errors.ts:notFound(entityType, idOrName)alreadyExists(entityType, name)validationFailed(message, details?)
Create libswamp directories:
data/,vaults/,extensions/,repo/Batch 1: Simple Read-Only Gets (~10 commands)
Pattern: resolve entity by ID/name -> not found = error -> found = completed with data. Reuse existing data structures from
*_output.tsas event payloads.-
model get—model_get.ts+model_get_output.ts -
workflow get—workflow_get.ts+workflow_get_output.ts -
vault get—vault_get.ts+vault_get_output.ts -
data get—data_get.ts+data_get_output.ts(two paths: model-scoped vs workflow-scoped, handle via input) -
model output get—model_output_get.ts+model_output_get_output.ts(partial-ID matching is domain logic) -
workflow history get—workflow_history_get.ts -
model method history get—model_method_history_get.ts -
model method describe—model_method_describe.ts+model_method_describe_output.ts -
type describe—type_describe.ts+type_describe_output.ts -
vault describe—vault_describe_output.ts
-
Batch 2: List/Versions/Validate/Stats (~12 commands)
Pattern: collection results, possibly multi-step aggregation. Validate commands need
validation_resultevent kind. Log commands injectLogFileReaderthrough deps.-
data list—data_list.ts+data_list_output.ts -
data versions—data_versions.ts+data_versions_output.ts -
vault list-keys—vault_list_keys.ts+vault_list_keys_output.ts -
extension list—extension_list.ts+extension_list_output.ts -
model validate—model_validate.ts+model_validate_output.ts -
workflow validate—workflow_validate.ts+workflow_validate_output.ts -
workflow schema—workflow_schema.ts+workflow_schema_output.ts -
workflow history logs—workflow_history_logs.ts -
model method history logs—model_method_history_logs.ts -
model output logs—model_output_logs.ts -
model output data—model_output_data.ts -
telemetry stats—telemetry_stats.ts+telemetry_stats_output.ts
-
Batch 3: Simple Mutations (~7 commands)
Pattern: validate -> create/mutate -> save -> yield completed.
model createinjectsresolveModelTypeas dep.vault createresolves provider config in generator.-
model create—model_create.ts+model_create_output.ts -
workflow create—workflow_create.ts+workflow_create_output.ts -
vault create—vault_create.ts+vault_create_output.ts -
data rename—data_rename.ts+data_rename_output.ts -
auth logout—auth_logout.ts -
repo init—repo_init.ts+repo_output.ts -
version—version.ts
-
Batch 4: Search Commands (~11 commands)
Pattern: generator fetches + filters, yields
completedwith results. Three renderer classes per command:JsonXxxRenderer(serializes),InkXxxRenderer/TuiXxxRenderer(interactive TUI — its own class, not a log renderer), and optionally a plainLogXxxRendererfor non-TTY log output. The Ink renderer's asynccompletedhandler launches the TUI and stores the selection. Extended interface:selectedItem(): T | undefined. Factory selects Ink renderer when in log mode with TTY. CLI chains follow-up generator if needed..tsxcomponents move tosrc/presentation/renderers/.-
model search—model_search.ts+model_search_output.tsx -
vault search—vault_search.ts+vault_search_output.tsx -
data search—data_search.ts+data_search_output.tsx -
workflow search—workflow_search.ts+workflow_search_output.tsx(follow-up: run workflow) -
extension search—extension_search.ts+extension_search_output.tsx(follow-up: install) -
type search—type_search.ts+type_search_output.tsx -
vault type search—vault_type_search.ts+vault_type_search_output.tsx -
model method history search—model_method_history_search.ts+model_output_search_output.tsx -
model output search—model_output_search.ts+model_output_search_output.tsx -
workflow history search—workflow_history_search.ts+workflow_history_search_output.tsx -
workflow run search—workflow_run_search.ts
-
Batch 5: Confirmation-Guarded Mutations (~6 commands)
Pattern: two-phase (preview generator -> CLI prompt -> execute generator) or single-phase with pre-check.
extension pullhas recursive deps + conflict detection (most complex).-
model delete—model_delete.ts+model_delete_output.ts -
workflow delete—workflow_delete.ts+workflow_delete_output.ts -
vault put—vault_put.ts+vault_put_output.ts -
data gc—data_gc.ts+data_gc_output.ts -
extension pull—extension_pull.ts+extension_pull_output.ts -
extension rm—extension_rm.ts+extension_rm_output.ts
-
Batch 6: Edit Commands (~3 commands)
Pattern: generator resolves entity + handles stdin/editor via
deps.openEditor(path). Search-first mode (no arg): chain search renderer ->selectedItem()-> edit generator.-
model edit—model_edit.ts+model_edit_output.ts -
workflow edit—workflow_edit.ts+workflow_edit_output.ts -
vault edit—vault_edit.ts+vault_edit_output.ts
-
Batch 7: Complex Evaluation (~2 commands)
Pattern: generator takes single/all mode in input. CEL evaluation + definition caching in generator. Locking injected through deps. Most domain-logic-heavy generators.
-
model evaluate—model_evaluate.ts+model_evaluate_output.ts -
workflow evaluate—workflow_evaluate.ts+workflow_evaluate_output.ts
-
Batch 8: Remaining Commands (~15 commands)
Mixed bag: auth login (browser flow via deps), audit/summarise (aggregation in generator), extensions (API calls via deps), datastore (S3 via deps), source, issue, update.
-
auth login—auth_login.ts+auth_login_output.ts -
audit—audit.ts+audit_output.ts -
summarise—summarise.ts+summarise_output.ts -
extension push—extension_push.ts+extension_push_output.ts -
extension update—extension_update.ts+extension_update_output.ts -
extension yank—extension_yank.ts+extension_yank_output.ts -
extension fmt—extension_fmt.ts+extension_fmt_output.ts -
datastore setup—datastore_setup.ts+datastore_output.ts -
datastore status—datastore_status.ts+datastore_output.ts -
datastore sync—datastore_sync.ts+datastore_output.ts -
datastore lock—datastore_lock.ts+datastore_output.ts -
source path/fetch/clean—source_*.ts+source_output.ts -
issue bug/feature—issue_*.ts+issue_output.ts -
update—update.ts+update_output.ts
-
Reference Implementations
| Command | Generator | Renderer |
|---|---|---|
auth whoami |
src/libswamp/auth/whoami.ts |
src/presentation/renderers/auth_whoami.ts |
model method run |
src/libswamp/models/run.ts |
src/presentation/renderers/model_method_run.ts |
workflow run |
src/libswamp/workflows/run.ts |
src/presentation/renderers/workflow_run.ts |
Key Infrastructure
src/libswamp/context.ts—LibSwampContext,createLibSwampContext()src/libswamp/stream.ts—consumeStream,EventHandlers,result,withDefaultssrc/libswamp/errors.ts—SwampError+ error factoriessrc/libswamp/testing.ts—collect,assertCompletes,assertErrorssrc/presentation/renderer.ts—Renderer<E>interface
Design Docs
design/libswamp.md— Event stream architecture, generator pattern, deps injectiondesign/rendering.md— Renderer interface, factory pattern, logging boundaries
Open
No activity in this phase yet.
Sign in to post a ripple.