2026-06-11 15:14:27 +03:00
//! Human/JSON output formatting for every command (moved verbatim from
//! main.rs in the modularization).
use super ::* ;
#[ derive(Debug, Serialize) ]
pub ( crate ) struct LoadOutput {
pub ( crate ) uri : String ,
pub ( crate ) branch : String ,
pub ( crate ) mode : & 'static str ,
/// Present only when `--from` was given; echoes the requested base.
#[ serde(skip_serializing_if = " Option::is_none " ) ]
pub ( crate ) base_branch : Option < String > ,
pub ( crate ) branch_created : bool ,
pub ( crate ) nodes_loaded : usize ,
pub ( crate ) edges_loaded : usize ,
pub ( crate ) node_types_loaded : usize ,
pub ( crate ) edge_types_loaded : usize ,
}
pub ( crate ) fn load_output_from_tables (
uri : & str ,
branch : & str ,
2026-06-13 17:05:32 +03:00
mode : & 'static str ,
2026-06-11 15:14:27 +03:00
output : & IngestOutput ,
) -> LoadOutput {
let mut nodes_loaded = 0 ;
let mut edges_loaded = 0 ;
let mut node_types_loaded = 0 ;
let mut edge_types_loaded = 0 ;
for table in & output . tables {
if table . table_key . starts_with ( " node: " ) {
nodes_loaded + = table . rows_loaded ;
node_types_loaded + = 1 ;
} else if table . table_key . starts_with ( " edge: " ) {
edges_loaded + = table . rows_loaded ;
edge_types_loaded + = 1 ;
}
}
LoadOutput {
uri : uri . to_string ( ) ,
branch : branch . to_string ( ) ,
2026-06-13 17:05:32 +03:00
mode ,
2026-06-11 15:14:27 +03:00
base_branch : output . base_branch . clone ( ) ,
branch_created : output . branch_created ,
nodes_loaded ,
edges_loaded ,
node_types_loaded ,
edge_types_loaded ,
}
}
2026-06-13 17:05:32 +03:00
/// The local arm's twin of `load_output_from_tables`: build the same
/// `LoadOutput` from the engine `LoadResult` directly (the remote arm only
/// has the wire `IngestOutput`'s table list; the local arm has the full
/// result). Both load mappings live here, next to the struct — RFC-009
/// Phase 2's "one place" for the `-> LoadOutput` mapping that used to fork
/// between this file and main.rs's inline construction.
pub ( crate ) fn load_output_from_result (
uri : & str ,
branch : & str ,
mode : & 'static str ,
result : & omnigraph ::loader ::LoadResult ,
) -> LoadOutput {
LoadOutput {
uri : uri . to_string ( ) ,
branch : branch . to_string ( ) ,
mode ,
base_branch : result . base_branch . clone ( ) ,
branch_created : result . branch_created ,
nodes_loaded : result . nodes_loaded . values ( ) . sum ( ) ,
edges_loaded : result . edges_loaded . values ( ) . sum ( ) ,
node_types_loaded : result . nodes_loaded . len ( ) ,
edge_types_loaded : result . edges_loaded . len ( ) ,
}
}
2026-06-11 15:14:27 +03:00
#[ derive(Debug, Serialize) ]
pub ( crate ) struct SchemaPlanOutput < ' a > {
pub ( crate ) uri : & ' a str ,
pub ( crate ) supported : bool ,
pub ( crate ) step_count : usize ,
pub ( crate ) steps : & ' a [ SchemaMigrationStep ] ,
}
pub ( crate ) fn print_schema_apply_human ( output : & SchemaApplyOutput ) {
println! ( " schema apply for {} " , output . uri ) ;
println! ( " supported: {} " , if output . supported { " yes " } else { " no " } ) ;
println! ( " applied: {} " , if output . applied { " yes " } else { " no " } ) ;
println! ( " manifest_version: {} " , output . manifest_version ) ;
if output . steps . is_empty ( ) {
println! ( " no schema changes " ) ;
return ;
}
for step in & output . steps {
println! ( " - {} " , render_schema_plan_step ( step ) ) ;
}
}
pub ( crate ) fn query_kind_label ( kind : QueryLintQueryKind ) -> & 'static str {
match kind {
QueryLintQueryKind ::Read = > " read " ,
QueryLintQueryKind ::Mutation = > " mutation " ,
}
}
pub ( crate ) fn severity_label ( severity : QueryLintSeverity ) -> & 'static str {
match severity {
QueryLintSeverity ::Error = > " ERROR " ,
QueryLintSeverity ::Warning = > " WARN " ,
QueryLintSeverity ::Info = > " INFO " ,
}
}
pub ( crate ) fn print_query_lint_human ( output : & QueryLintOutput ) {
for result in & output . results {
match result . status {
QueryLintStatus ::Ok = > {
println! (
" OK query `{}` ({}) " ,
result . name ,
query_kind_label ( result . kind )
) ;
}
QueryLintStatus ::Error = > {
println! (
" ERROR query `{}`: {} " ,
result . name ,
result . error . as_deref ( ) . unwrap_or ( " unknown error " )
) ;
}
}
for warning in & result . warnings {
println! ( " WARN query ` {} `: {} " , result . name , warning ) ;
}
}
for finding in & output . findings {
println! ( " {} {} " , severity_label ( finding . severity ) , finding . message ) ;
}
println! (
" INFO Lint complete: {} queries processed ({} error(s), {} warning(s), {} info item(s)) " ,
output . queries_processed , output . errors , output . warnings , output . infos
) ;
}
pub ( crate ) fn finish_query_lint ( output : & QueryLintOutput , json : bool ) -> Result < ( ) > {
if json {
print_json ( output ) ? ;
} else {
print_query_lint_human ( output ) ;
}
if output . status = = QueryLintStatus ::Error {
io ::stdout ( ) . flush ( ) ? ;
std ::process ::exit ( 1 ) ;
}
Ok ( ( ) )
}
pub ( crate ) fn print_json < T : Serialize > ( value : & T ) -> Result < ( ) > {
println! ( " {} " , serde_json ::to_string_pretty ( value ) ? ) ;
Ok ( ( ) )
}
pub ( crate ) fn print_cluster_validate_human ( output : & ValidateOutput ) {
if output . ok {
println! (
" cluster config valid: {} resource(s), {} dependency edge(s) " ,
output . resources . len ( ) ,
output . dependencies . len ( )
) ;
} else {
println! ( " cluster config invalid " ) ;
}
print_cluster_diagnostics ( & output . diagnostics ) ;
}
pub ( crate ) fn print_cluster_plan_human ( output : & PlanOutput ) {
if output . ok {
println! (
" cluster plan: {} change(s), {} approval gate(s) " ,
output . changes . len ( ) ,
output . approvals_required . len ( )
) ;
for change in & output . changes {
let bindings = if change . binding_change { " [bindings] " } else { " " } ;
println! ( " {:?} {} {bindings} " , change . operation , change . resource ) ;
if let Some ( migration ) = & change . migration {
if ! migration . supported {
println! ( " migration UNSUPPORTED: " ) ;
}
for step in & migration . steps {
println! (
" {} " ,
serde_json ::to_string ( step ) . unwrap_or_else ( | _ | format! ( " {step:?} " ) )
) ;
}
}
}
if output . changes . is_empty ( ) {
println! ( " no changes " ) ;
}
} else {
println! ( " cluster plan failed " ) ;
}
print_cluster_diagnostics ( & output . diagnostics ) ;
}
pub ( crate ) fn print_cluster_apply_human ( output : & ApplyOutput ) {
if output . ok {
println! (
" cluster apply: {} applied, {} deferred/blocked " ,
output . applied_count , output . deferred_count
) ;
} else {
println! ( " cluster apply failed " ) ;
}
// The change list prints on failure too: an operator debugging a partial
// apply (payload or state-write error) needs to see what was attempted.
print_cluster_apply_changes ( & output . changes ) ;
if output . ok {
let state = & output . state_observations ;
println! (
" state: revision {}, converged: {}, written: {} " ,
state . state_revision , output . converged , output . state_written
) ;
println! ( " note: cluster-booted servers (--cluster) serve this on their next restart; omnigraph.yaml deployments are unaffected " ) ;
}
print_cluster_diagnostics ( & output . diagnostics ) ;
}
pub ( crate ) fn print_cluster_apply_changes ( changes : & [ omnigraph_cluster ::PlanChange ] ) {
for change in changes {
let bindings = if change . binding_change { " [bindings] " } else { " " } ;
match ( & change . disposition , change . reason . as_deref ( ) ) {
( Some ( disposition ) , Some ( reason ) ) = > println! (
" {:?} {}{bindings} [{disposition:?}: {reason}] " ,
change . operation , change . resource
) ,
( Some ( disposition ) , None ) = > println! (
" {:?} {}{bindings} [{disposition:?}] " ,
change . operation , change . resource
) ,
_ = > println! ( " {:?} {} {bindings} " , change . operation , change . resource ) ,
}
}
if changes . is_empty ( ) {
println! ( " no changes " ) ;
}
}
pub ( crate ) fn print_cluster_status_human ( output : & StatusOutput ) {
if output . ok {
let state = & output . state_observations ;
if state . state_found {
println! (
" cluster state: revision {}, {} resource(s) " ,
state . state_revision , state . resource_count
) ;
if let Some ( digest ) = state . applied_config_digest . as_deref ( ) {
println! ( " applied config: {digest} " ) ;
}
if state . locked {
println! ( " lock: held {} " , cluster_lock_summary ( state ) ) ;
} else {
println! ( " lock: not held " ) ;
}
} else {
println! ( " cluster state missing " ) ;
}
} else {
println! ( " cluster status failed " ) ;
}
print_cluster_diagnostics ( & output . diagnostics ) ;
}
pub ( crate ) fn print_cluster_state_sync_human ( output : & StateSyncOutput ) {
let operation = match output . operation {
omnigraph_cluster ::StateSyncOperation ::Refresh = > " refresh " ,
omnigraph_cluster ::StateSyncOperation ::Import = > " import " ,
} ;
if output . ok {
let state = & output . state_observations ;
println! (
" cluster {operation}: revision {}, {} resource(s) " ,
state . state_revision , state . resource_count
) ;
if let Some ( cas ) = state . state_cas . as_deref ( ) {
println! ( " state_cas: {cas} " ) ;
}
if state . locked {
println! ( " lock: acquired {} " , cluster_lock_summary ( state ) ) ;
} else {
println! ( " lock: not acquired " ) ;
}
} else {
println! ( " cluster {operation} failed " ) ;
}
print_cluster_diagnostics ( & output . diagnostics ) ;
}
pub ( crate ) fn print_cluster_force_unlock_human ( output : & ForceUnlockOutput ) {
if output . ok {
if output . lock_removed {
println! (
" cluster force-unlock: removed lock{} " ,
cluster_lock_summary ( & output . state_observations )
) ;
} else {
println! ( " cluster force-unlock: no lock removed " ) ;
}
} else {
println! ( " cluster force-unlock failed " ) ;
if output . state_observations . locked {
println! (
" lock: held{} " ,
cluster_lock_summary ( & output . state_observations )
) ;
}
}
print_cluster_diagnostics ( & output . diagnostics ) ;
}
pub ( crate ) fn cluster_lock_summary ( state : & omnigraph_cluster ::StateObservations ) -> String {
let Some ( lock_id ) = state . lock_id . as_deref ( ) else {
return String ::new ( ) ;
} ;
let mut parts = vec! [ format! ( " id= {lock_id} " ) ] ;
if let Some ( operation ) = state . lock_operation . as_deref ( ) {
parts . push ( format! ( " operation= {operation} " ) ) ;
}
if let Some ( pid ) = state . lock_pid {
parts . push ( format! ( " pid= {pid} " ) ) ;
}
if let Some ( created_at ) = state . lock_created_at . as_deref ( ) {
parts . push ( format! ( " created_at= {created_at} " ) ) ;
}
if let Some ( age_seconds ) = state . lock_age_seconds {
parts . push ( format! ( " age_seconds= {age_seconds} " ) ) ;
}
format! ( " ( {} ) " , parts . join ( " , " ) )
}
pub ( crate ) fn print_cluster_diagnostics ( diagnostics : & [ omnigraph_cluster ::Diagnostic ] ) {
for diagnostic in diagnostics {
let label = match diagnostic . severity {
DiagnosticSeverity ::Error = > " ERROR " ,
DiagnosticSeverity ::Warning = > " WARN " ,
} ;
println! (
" {label} {} {}: {} " ,
diagnostic . code , diagnostic . path , diagnostic . message
) ;
}
}
pub ( crate ) fn finish_cluster_validate ( output : & ValidateOutput , json : bool ) -> Result < ( ) > {
if json {
print_json ( output ) ? ;
} else {
print_cluster_validate_human ( output ) ;
}
if ! output . ok {
io ::stdout ( ) . flush ( ) ? ;
std ::process ::exit ( 1 ) ;
}
Ok ( ( ) )
}
pub ( crate ) fn finish_cluster_plan ( output : & PlanOutput , json : bool ) -> Result < ( ) > {
if json {
print_json ( output ) ? ;
} else {
print_cluster_plan_human ( output ) ;
}
if ! output . ok {
io ::stdout ( ) . flush ( ) ? ;
std ::process ::exit ( 1 ) ;
}
Ok ( ( ) )
}
pub ( crate ) fn finish_cluster_apply ( output : & ApplyOutput , json : bool ) -> Result < ( ) > {
if json {
print_json ( output ) ? ;
} else {
print_cluster_apply_human ( output ) ;
}
if ! output . ok {
io ::stdout ( ) . flush ( ) ? ;
std ::process ::exit ( 1 ) ;
}
Ok ( ( ) )
}
pub ( crate ) fn finish_cluster_approve ( output : & ApproveOutput , json : bool ) -> Result < ( ) > {
if json {
print_json ( output ) ? ;
} else if output . ok {
println! (
" cluster approve: {} {} approved by {} (approval {}) " ,
output
. operation
. as_ref ( )
. map ( | operation | format! ( " {operation:?} " ) . to_lowercase ( ) )
. unwrap_or_default ( ) ,
output . resource . as_deref ( ) . unwrap_or ( " ? " ) ,
output . approved_by . as_deref ( ) . unwrap_or ( " ? " ) ,
output . approval_id . as_deref ( ) . unwrap_or ( " ? " ) ,
) ;
print_cluster_diagnostics ( & output . diagnostics ) ;
} else {
println! ( " cluster approve failed " ) ;
print_cluster_diagnostics ( & output . diagnostics ) ;
}
if ! output . ok {
io ::stdout ( ) . flush ( ) ? ;
std ::process ::exit ( 1 ) ;
}
Ok ( ( ) )
}
pub ( crate ) fn finish_cluster_status ( output : & StatusOutput , json : bool ) -> Result < ( ) > {
if json {
print_json ( output ) ? ;
} else {
print_cluster_status_human ( output ) ;
}
if ! output . ok {
io ::stdout ( ) . flush ( ) ? ;
std ::process ::exit ( 1 ) ;
}
Ok ( ( ) )
}
pub ( crate ) fn finish_cluster_state_sync ( output : & StateSyncOutput , json : bool ) -> Result < ( ) > {
if json {
print_json ( output ) ? ;
} else {
print_cluster_state_sync_human ( output ) ;
}
if ! output . ok {
io ::stdout ( ) . flush ( ) ? ;
std ::process ::exit ( 1 ) ;
}
Ok ( ( ) )
}
pub ( crate ) fn finish_cluster_force_unlock ( output : & ForceUnlockOutput , json : bool ) -> Result < ( ) > {
if json {
print_json ( output ) ? ;
} else {
print_cluster_force_unlock_human ( output ) ;
}
if ! output . ok {
io ::stdout ( ) . flush ( ) ? ;
std ::process ::exit ( 1 ) ;
}
Ok ( ( ) )
}
pub ( crate ) fn print_load_human ( payload : & LoadOutput ) {
println! (
" loaded {} on branch {} with {}: {} nodes across {} node types, {} edges across {} edge types " ,
payload . uri ,
payload . branch ,
payload . mode ,
payload . nodes_loaded ,
payload . node_types_loaded ,
payload . edges_loaded ,
payload . edge_types_loaded
) ;
if payload . branch_created {
if let Some ( base ) = & payload . base_branch {
println! ( " branch {} created from {} " , payload . branch , base ) ;
}
}
}
pub ( crate ) fn print_ingest_human ( output : & IngestOutput ) {
println! (
" ingested {} into branch {} from {} with {} ({}) " ,
output . uri ,
output . branch ,
output . base_branch . as_deref ( ) . unwrap_or ( " main " ) ,
output . mode . as_str ( ) ,
if output . branch_created {
" branch created "
} else {
" branch exists "
}
) ;
for table in & output . tables {
println! ( " {} rows_loaded= {} " , table . table_key , table . rows_loaded ) ;
}
if let Some ( actor_id ) = & output . actor_id {
println! ( " actor_id: {} " , actor_id ) ;
}
}
pub ( crate ) fn print_schema_plan_human ( uri : & str , plan : & SchemaMigrationPlan ) {
println! ( " schema plan for {} " , uri ) ;
println! ( " supported: {} " , if plan . supported { " yes " } else { " no " } ) ;
if plan . steps . is_empty ( ) {
println! ( " no schema changes " ) ;
return ;
}
for step in & plan . steps {
println! ( " - {} " , render_schema_plan_step ( step ) ) ;
}
}
pub ( crate ) fn render_schema_plan_step ( step : & SchemaMigrationStep ) -> String {
match step {
SchemaMigrationStep ::AddType { type_kind , name } = > {
format! ( " add {} type ' {} ' " , schema_type_kind_label ( * type_kind ) , name )
}
SchemaMigrationStep ::RenameType {
type_kind ,
from ,
to ,
} = > format! (
" rename {} type '{}' -> '{}' " ,
schema_type_kind_label ( * type_kind ) ,
from ,
to
) ,
SchemaMigrationStep ::AddProperty {
type_kind ,
type_name ,
property_name ,
property_type ,
} = > format! (
" add property '{}.{}' ({}) on {} '{}' " ,
type_name ,
property_name ,
render_prop_type ( property_type ) ,
schema_type_kind_label ( * type_kind ) ,
type_name
) ,
SchemaMigrationStep ::RenameProperty {
type_kind ,
type_name ,
from ,
to ,
} = > format! (
" rename property '{}.{}' -> '{}.{}' on {} '{}' " ,
type_name ,
from ,
type_name ,
to ,
schema_type_kind_label ( * type_kind ) ,
type_name
) ,
SchemaMigrationStep ::AddConstraint {
type_kind ,
type_name ,
constraint ,
} = > format! (
" add constraint {} on {} '{}' " ,
render_constraint ( constraint ) ,
schema_type_kind_label ( * type_kind ) ,
type_name
) ,
SchemaMigrationStep ::UpdateTypeMetadata {
type_kind ,
name ,
annotations ,
} = > format! (
" update metadata on {} '{}' ({}) " ,
schema_type_kind_label ( * type_kind ) ,
name ,
render_annotations ( annotations )
) ,
SchemaMigrationStep ::UpdatePropertyMetadata {
type_kind ,
type_name ,
property_name ,
annotations ,
} = > format! (
" update metadata on property '{}.{}' of {} '{}' ({}) " ,
type_name ,
property_name ,
schema_type_kind_label ( * type_kind ) ,
type_name ,
render_annotations ( annotations )
) ,
SchemaMigrationStep ::DropType {
type_kind ,
name ,
mode ,
} = > format! (
" drop {} type '{}' ({} mode) " ,
schema_type_kind_label ( * type_kind ) ,
name ,
drop_mode_label ( * mode ) ,
) ,
SchemaMigrationStep ::DropProperty {
type_kind ,
type_name ,
property_name ,
mode ,
} = > format! (
" drop property '{}.{}' of {} '{}' ({} mode) " ,
type_name ,
property_name ,
schema_type_kind_label ( * type_kind ) ,
type_name ,
drop_mode_label ( * mode ) ,
) ,
SchemaMigrationStep ::UnsupportedChange { entity , reason , .. } = > {
// When a schema-lint code is attached, render code + tier
// so operators see at-a-glance the kind of risk (destructive
// / validated / safe) — not just the rule identifier.
// Reach the diagnostic via the `diagnostic()` helper so the
// CLI doesn't need to know how the lookup works.
match step . diagnostic ( ) {
Some ( diag ) = > format! (
" unsupported change on {} [{}, {}]: {} " ,
entity ,
diag . code ,
schema_lint_tier_label ( diag . tier ) ,
reason ,
) ,
None = > format! ( " unsupported change on {} : {} " , entity , reason ) ,
}
}
}
}
pub ( crate ) fn schema_type_kind_label ( kind : omnigraph_compiler ::SchemaTypeKind ) -> & 'static str {
match kind {
omnigraph_compiler ::SchemaTypeKind ::Interface = > " interface " ,
omnigraph_compiler ::SchemaTypeKind ::Node = > " node " ,
omnigraph_compiler ::SchemaTypeKind ::Edge = > " edge " ,
}
}
pub ( crate ) fn schema_lint_tier_label ( tier : omnigraph_compiler ::SafetyTier ) -> & 'static str {
match tier {
omnigraph_compiler ::SafetyTier ::Safe = > " safe " ,
omnigraph_compiler ::SafetyTier ::Validated = > " validated " ,
omnigraph_compiler ::SafetyTier ::Destructive = > " destructive " ,
}
}
pub ( crate ) fn drop_mode_label ( mode : omnigraph_compiler ::DropMode ) -> & 'static str {
match mode {
omnigraph_compiler ::DropMode ::Soft = > " soft " ,
omnigraph_compiler ::DropMode ::Hard = > " hard " ,
}
}
pub ( crate ) fn render_prop_type ( prop_type : & omnigraph_compiler ::PropType ) -> String {
let base = if let Some ( values ) = & prop_type . enum_values {
format! ( " Enum( {} ) " , values . join ( " | " ) )
} else {
prop_type . scalar . to_string ( )
} ;
let base = if prop_type . list {
format! ( " [ {} ] " , base )
} else {
base
} ;
if prop_type . nullable {
format! ( " {} ? " , base )
} else {
base
}
}
pub ( crate ) fn render_constraint ( constraint : & omnigraph_compiler ::schema ::ast ::Constraint ) -> String {
match constraint {
omnigraph_compiler ::schema ::ast ::Constraint ::Key ( columns ) = > {
format! ( " @key( {} ) " , columns . join ( " , " ) )
}
omnigraph_compiler ::schema ::ast ::Constraint ::Unique ( columns ) = > {
format! ( " @unique( {} ) " , columns . join ( " , " ) )
}
omnigraph_compiler ::schema ::ast ::Constraint ::Index ( columns ) = > {
format! ( " @index( {} ) " , columns . join ( " , " ) )
}
omnigraph_compiler ::schema ::ast ::Constraint ::Range { property , min , max } = > {
format! ( " @range( {} , {:?} , {:?} ) " , property , min , max )
}
omnigraph_compiler ::schema ::ast ::Constraint ::Check { property , pattern } = > {
format! ( " @check( {} , {:?} ) " , property , pattern )
}
}
}
pub ( crate ) fn render_annotations ( annotations : & [ omnigraph_compiler ::schema ::ast ::Annotation ] ) -> String {
annotations
. iter ( )
. map ( | annotation | match & annotation . value {
Some ( value ) = > format! ( " @ {} ( {} ) " , annotation . name , value ) ,
None = > format! ( " @ {} " , annotation . name ) ,
} )
. collect ::< Vec < _ > > ( )
. join ( " , " )
}
pub ( crate ) fn print_embed_human ( output : & EmbedOutput ) {
println! (
" embedded {} rows (selected {}, cleaned {}) from {} -> {} [{} {}d] " ,
output . embedded_rows ,
output . selected_rows ,
output . cleaned_rows ,
output . input ,
output . output ,
output . mode ,
output . dimension
) ;
}
pub ( crate ) fn print_snapshot_human ( branch : & str , manifest_version : u64 , entries : & [ SnapshotTableOutput ] ) {
println! ( " branch: {} " , branch ) ;
println! ( " manifest_version: {} " , manifest_version ) ;
for entry in entries {
println! (
" {} v{} branch={} rows={} " ,
entry . table_key ,
entry . table_version ,
entry . table_branch . as_deref ( ) . unwrap_or ( " main " ) ,
entry . row_count
) ;
}
}
pub ( crate ) fn print_read_output (
output : & ReadOutput ,
format : ReadOutputFormat ,
config : & OmnigraphConfig ,
) -> Result < ( ) > {
println! (
" {} " ,
render_read (
output ,
format ,
2026-06-11 23:32:05 +03:00
& resolve_table_render_options ( config ) ,
2026-06-11 15:14:27 +03:00
) ?
) ;
Ok ( ( ) )
}
pub ( crate ) fn print_change_human ( output : & ChangeOutput ) {
println! (
" changed {} via {}: {} nodes, {} edges " ,
output . branch , output . query_name , output . affected_nodes , output . affected_edges
) ;
if let Some ( actor_id ) = & output . actor_id {
println! ( " actor_id: {} " , actor_id ) ;
}
}
pub ( crate ) fn print_commit_list_human ( commits : & [ CommitOutput ] ) {
for commit in commits {
let branch = commit . manifest_branch . as_deref ( ) . unwrap_or ( " main " ) ;
println! (
" {} branch={} version={}{} " ,
commit . graph_commit_id ,
branch ,
commit . manifest_version ,
commit
. actor_id
. as_deref ( )
. map ( | actor | format! ( " actor= {} " , actor ) )
. unwrap_or_default ( )
) ;
}
}
pub ( crate ) fn print_commit_human ( commit : & CommitOutput ) {
println! ( " graph_commit_id: {} " , commit . graph_commit_id ) ;
println! (
" manifest_branch: {} " ,
commit . manifest_branch . as_deref ( ) . unwrap_or ( " main " )
) ;
println! ( " manifest_version: {} " , commit . manifest_version ) ;
if let Some ( parent_commit_id ) = & commit . parent_commit_id {
println! ( " parent_commit_id: {} " , parent_commit_id ) ;
}
if let Some ( merged_parent_commit_id ) = & commit . merged_parent_commit_id {
println! ( " merged_parent_commit_id: {} " , merged_parent_commit_id ) ;
}
if let Some ( actor_id ) = & commit . actor_id {
println! ( " actor_id: {} " , actor_id ) ;
}
println! ( " created_at: {} " , commit . created_at ) ;
}
pub ( crate ) fn print_policy_explain ( decision : & PolicyDecision , actor_id : & str , request : & PolicyRequest ) {
println! (
" decision: {} " ,
if decision . allowed { " allow " } else { " deny " }
) ;
println! ( " actor: {} " , actor_id ) ;
println! ( " action: {} " , request . action ) ;
if let Some ( branch ) = & request . branch {
println! ( " branch: {} " , branch ) ;
}
if let Some ( target_branch ) = & request . target_branch {
println! ( " target_branch: {} " , target_branch ) ;
}
if let Some ( rule_id ) = & decision . matched_rule_id {
println! ( " matched_rule: {} " , rule_id ) ;
}
println! ( " message: {} " , decision . message ) ;
}
#[ derive(serde::Serialize) ]
pub ( crate ) struct QueriesIssue {
pub ( crate ) query : String ,
pub ( crate ) message : String ,
}
#[ derive(serde::Serialize) ]
pub ( crate ) struct QueriesValidateOutput {
pub ( crate ) ok : bool ,
pub ( crate ) breakages : Vec < QueriesIssue > ,
pub ( crate ) warnings : Vec < QueriesIssue > ,
}
#[ derive(serde::Serialize) ]
pub ( crate ) struct QueriesParam {
pub ( crate ) name : String ,
#[ serde(rename = " type " ) ]
pub ( crate ) type_name : String ,
pub ( crate ) nullable : bool ,
}
#[ derive(serde::Serialize) ]
pub ( crate ) struct QueriesListItem {
pub ( crate ) name : String ,
pub ( crate ) mcp_expose : bool ,
pub ( crate ) tool_name : Option < String > ,
pub ( crate ) mutation : bool ,
pub ( crate ) params : Vec < QueriesParam > ,
}
#[ derive(serde::Serialize) ]
pub ( crate ) struct QueriesListOutput {
pub ( crate ) queries : Vec < QueriesListItem > ,
}
2026-06-11 21:24:51 +03:00
pub ( crate ) fn finish_login (
server : & str ,
credentials_path : & std ::path ::Path ,
declared : bool ,
json : bool ,
) -> Result < ( ) > {
if json {
print_json ( & serde_json ::json! ( {
" server " : server ,
" credentials_path " : credentials_path . display ( ) . to_string ( ) ,
" declared " : declared ,
} ) ) ? ;
} else {
println! (
" stored credential for '{server}' in {} " ,
credentials_path . display ( )
) ;
}
if ! declared {
eprintln! (
" note: '{server}' is not declared under servers: in the operator config; the token applies once you add `servers: \n {server}: \n url: <server url>` to ~/.omnigraph/config.yaml "
) ;
}
Ok ( ( ) )
}
pub ( crate ) fn finish_logout (
server : & str ,
credentials_path : & std ::path ::Path ,
json : bool ,
) -> Result < ( ) > {
if json {
print_json ( & serde_json ::json! ( {
" server " : server ,
" credentials_path " : credentials_path . display ( ) . to_string ( ) ,
} ) ) ? ;
} else {
println! (
" removed credential for '{server}' from {} " ,
credentials_path . display ( )
) ;
}
Ok ( ( ) )
}
2026-06-11 23:32:05 +03:00
/// Table prefs cascade (RFC-007/008): legacy cli.table_* (window) >
/// operator defaults.table_* > built-in.
pub ( crate ) fn resolve_table_render_options ( config : & OmnigraphConfig ) -> ReadRenderOptions {
let operator = crate ::operator ::load_operator_config ( ) . unwrap_or_default ( ) ;
ReadRenderOptions {
max_column_width : config
. cli
. table_max_column_width
. or ( operator . defaults . table_max_column_width )
. unwrap_or ( 80 ) ,
cell_layout : config
. cli
. table_cell_layout
. or ( operator . defaults . table_cell_layout )
. unwrap_or_default ( ) ,
}
}