aspera-cli 4.27.1 → 4.27.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +67 -1
  4. data/bin/ascli +2 -1
  5. data/docs/README.md +805 -747
  6. data/lib/aspera/agent/connect.rb +6 -4
  7. data/lib/aspera/agent/desktop.rb +2 -2
  8. data/lib/aspera/agent/direct.rb +3 -1
  9. data/lib/aspera/agent/node.rb +3 -3
  10. data/lib/aspera/api/alee.rb +1 -1
  11. data/lib/aspera/api/aoc.rb +14 -12
  12. data/lib/aspera/api/ats.rb +1 -1
  13. data/lib/aspera/api/cos_node.rb +2 -2
  14. data/lib/aspera/api/faspex.rb +9 -7
  15. data/lib/aspera/api/httpgw.rb +37 -33
  16. data/lib/aspera/api/node.rb +38 -33
  17. data/lib/aspera/ascmd.rb +3 -1
  18. data/lib/aspera/ascp/installation.rb +62 -27
  19. data/lib/aspera/ascp/management.rb +1 -0
  20. data/lib/aspera/assert.rb +4 -0
  21. data/lib/aspera/cli/ascp_actions.rb +20 -41
  22. data/lib/aspera/cli/async_transfer_store.rb +2 -2
  23. data/lib/aspera/cli/bootstrapper.rb +11 -15
  24. data/lib/aspera/cli/command_line.rb +252 -0
  25. data/lib/aspera/cli/command_registry.rb +149 -33
  26. data/lib/aspera/cli/command_spec.rb +103 -14
  27. data/lib/aspera/cli/completion/ascli.bash +12 -0
  28. data/lib/aspera/cli/completion/ascli.fish +16 -0
  29. data/lib/aspera/cli/completion/ascli.zsh +19 -0
  30. data/lib/aspera/cli/context.rb +3 -0
  31. data/lib/aspera/cli/deprecation.rb +37 -0
  32. data/lib/aspera/cli/extended_value.rb +2 -0
  33. data/lib/aspera/cli/formatter.rb +87 -75
  34. data/lib/aspera/cli/gem_checker.rb +1 -1
  35. data/lib/aspera/cli/hints.rb +7 -6
  36. data/lib/aspera/cli/http.rb +21 -21
  37. data/lib/aspera/cli/info.rb +3 -0
  38. data/lib/aspera/cli/mcp_tool.rb +47 -83
  39. data/lib/aspera/cli/option_declarator.rb +33 -42
  40. data/lib/aspera/cli/option_registry.rb +69 -0
  41. data/lib/aspera/cli/option_types.rb +103 -0
  42. data/lib/aspera/cli/option_value.rb +281 -0
  43. data/lib/aspera/cli/options.schema.yaml +38 -5
  44. data/lib/aspera/cli/parser.rb +307 -848
  45. data/lib/aspera/cli/plugins/alee.rb +7 -4
  46. data/lib/aspera/cli/plugins/aoc.rb +435 -380
  47. data/lib/aspera/cli/plugins/ats.rb +58 -73
  48. data/lib/aspera/cli/plugins/base.rb +190 -240
  49. data/lib/aspera/cli/plugins/basic_auth.rb +2 -10
  50. data/lib/aspera/cli/plugins/config.rb +244 -178
  51. data/lib/aspera/cli/plugins/console.rb +102 -38
  52. data/lib/aspera/cli/plugins/cos.rb +6 -23
  53. data/lib/aspera/cli/plugins/factory.rb +3 -0
  54. data/lib/aspera/cli/plugins/faspex5.rb +176 -173
  55. data/lib/aspera/cli/plugins/faspio.rb +5 -10
  56. data/lib/aspera/cli/plugins/httpgw.rb +8 -11
  57. data/lib/aspera/cli/plugins/mcp.rb +20 -55
  58. data/lib/aspera/cli/plugins/node.rb +277 -311
  59. data/lib/aspera/cli/plugins/orchestrator.rb +90 -77
  60. data/lib/aspera/cli/plugins/preview.rb +79 -90
  61. data/lib/aspera/cli/plugins/server.rb +76 -50
  62. data/lib/aspera/cli/plugins/shares.rb +68 -116
  63. data/lib/aspera/cli/preset_actions.rb +17 -10
  64. data/lib/aspera/cli/preset_manager.rb +12 -2
  65. data/lib/aspera/cli/prompt.rb +35 -0
  66. data/lib/aspera/cli/result.rb +13 -18
  67. data/lib/aspera/cli/runner.rb +31 -54
  68. data/lib/aspera/cli/special_values.rb +5 -0
  69. data/lib/aspera/cli/sync_actions.rb +41 -37
  70. data/lib/aspera/cli/terminal_formatter.rb +9 -3
  71. data/lib/aspera/cli/transfer_actions.rb +0 -6
  72. data/lib/aspera/cli/transfer_agent.rb +29 -35
  73. data/lib/aspera/cli/vault_manager.rb +0 -17
  74. data/lib/aspera/cli/version.rb +1 -1
  75. data/lib/aspera/cli/wizard.rb +4 -2
  76. data/lib/aspera/command_line_builder.rb +1 -0
  77. data/lib/aspera/coverage.rb +1 -0
  78. data/lib/aspera/environment.rb +7 -1
  79. data/lib/aspera/faspex_gw.rb +2 -1
  80. data/lib/aspera/faspex_postproc.rb +1 -0
  81. data/lib/aspera/graphql.rb +5 -5
  82. data/lib/aspera/json_rpc/client.rb +5 -5
  83. data/lib/aspera/keychain/encrypted_hash.rb +1 -1
  84. data/lib/aspera/keychain/one_password_api.rb +1 -1
  85. data/lib/aspera/link_header.rb +2 -2
  86. data/lib/aspera/log.rb +22 -25
  87. data/lib/aspera/markdown.rb +2 -0
  88. data/lib/aspera/mime.rb +25 -0
  89. data/lib/aspera/node_simulator.rb +1 -0
  90. data/lib/aspera/oauth/base.rb +35 -25
  91. data/lib/aspera/oauth/factory.rb +1 -0
  92. data/lib/aspera/oauth/generic.rb +1 -1
  93. data/lib/aspera/oauth/jwt.rb +1 -1
  94. data/lib/aspera/oauth/web.rb +9 -8
  95. data/lib/aspera/preview/file_types.rb +4 -4
  96. data/lib/aspera/preview/generator.rb +7 -0
  97. data/lib/aspera/preview/options.rb +4 -4
  98. data/lib/aspera/preview/terminal.rb +4 -3
  99. data/lib/aspera/preview/utils.rb +9 -6
  100. data/lib/aspera/products/connect.rb +1 -1
  101. data/lib/aspera/rainbow.rb +7 -0
  102. data/lib/aspera/rest/aspera_errors.rb +60 -0
  103. data/lib/aspera/rest/call_error.rb +27 -0
  104. data/lib/aspera/rest/client.rb +514 -0
  105. data/lib/aspera/rest/error_analyzer.rb +113 -0
  106. data/lib/aspera/rest/list.rb +143 -0
  107. data/lib/aspera/rest/parameters.rb +55 -0
  108. data/lib/aspera/rest/util.rb +176 -0
  109. data/lib/aspera/rest.rb +7 -621
  110. data/lib/aspera/schema/IBM Aspera Console-enhanced.yaml +1125 -0
  111. data/lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml +39 -0
  112. data/lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml +2395 -0
  113. data/lib/aspera/schema/documentation.rb +13 -3
  114. data/lib/aspera/schema/registry.rb +18 -1
  115. data/lib/aspera/schema/validator.rb +92 -0
  116. data/lib/aspera/secret_hider.rb +36 -25
  117. data/lib/aspera/string_ext.rb +15 -0
  118. data/lib/aspera/temp_file_manager.rb +6 -5
  119. data/lib/aspera/transfer/parameters.rb +2 -0
  120. data/lib/aspera/transfer/spec.rb +1 -0
  121. data/lib/aspera/transfer/spec.schema.yaml +1 -0
  122. data/lib/aspera/uri_reader.rb +11 -11
  123. data/lib/aspera/web_auth/index.html +147 -0
  124. data/lib/aspera/web_auth/server.rb +81 -0
  125. data.tar.gz.sig +0 -0
  126. metadata +39 -7
  127. metadata.gz.sig +0 -0
  128. data/lib/aspera/colors.rb +0 -79
  129. data/lib/aspera/rest_call_error.rb +0 -25
  130. data/lib/aspera/rest_error_analyzer.rb +0 -111
  131. data/lib/aspera/rest_errors_aspera.rb +0 -58
  132. data/lib/aspera/rest_list.rb +0 -136
  133. data/lib/aspera/web_auth.rb +0 -211
@@ -0,0 +1,281 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aspera/cli/option_types'
4
+ require 'aspera/cli/extended_value'
5
+ require 'aspera/cli/deprecation'
6
+ require 'aspera/secret_hider'
7
+ require 'aspera/schema/registry'
8
+ require 'aspera/schema/validator'
9
+ require 'aspera/log'
10
+ require 'aspera/assert'
11
+ require 'aspera/rainbow'
12
+ using Rainbow
13
+
14
+ module Aspera
15
+ module Cli
16
+ # Declared option: type, value, and where the value is stored.
17
+ class OptionValue
18
+ # [Symbol] Name of option
19
+ attr_reader :option
20
+ # [Array<Class>, nil] List of allowed types, `nil` for no validation
21
+ attr_reader :types
22
+ # [Symbol] How values are converted: :flag, :boolean, :integer, :enum, :enum_list, :string_list, :other
23
+ attr_reader :kind
24
+ # [Symbol, nil] `OptionSource` of current value, `nil` if never set
25
+ attr_reader :source
26
+ attr_reader :sensitive, :schema, :deprecation
27
+ # [Array] List of allowed values (Symbols and specific values)
28
+ attr_accessor :values
29
+ # [String] Help section group name (set by OptionRegistry)
30
+ attr_accessor :group
31
+ # [String, nil] Short option char (set by OptionRegistry)
32
+ attr_accessor :short
33
+ # [Proc, nil] Block to call for flag options
34
+ attr_accessor :block
35
+
36
+ # @param option [Symbol] Name of option
37
+ # @param description [String, nil] Description for help; if nil, derived from schema
38
+ # @param allowed [nil,Class,Array<Class>,Array<Symbol>] Allowed values
39
+ # @param on_set [#call, nil] Called with the new value each time the value is set
40
+ # @param shorthand [String, nil] For a `Hash` option: a `String` value is stored as `{shorthand => value}`
41
+ # @param deprecation [Hash, Deprecation, nil] Deprecation: `{last:, message:}`, see `Deprecation`
42
+ # @param schema [String] Declaration of schema
43
+ # `allowed`:
44
+ # - `nil` No validation, so just a string
45
+ # - `Class` The single allowed Class
46
+ # - `Array<Class>` Multiple allowed classes
47
+ # - `Array<Symbol>` List of allowed values
48
+ def initialize(option:, description: nil, allowed: Type::STRING, on_set: nil, shorthand: nil, deprecation: nil, schema: nil)
49
+ Log.log.trace1 { "option: #{option}, allowed: #{allowed}" }
50
+ @option = option
51
+ @description = description
52
+ @group = nil
53
+ @short = nil
54
+ @block = nil
55
+ # by default passwords and secrets are sensitive, else specify when declaring the option
56
+ @sensitive = SecretHider.instance.secret?(@option, '')
57
+ @deprecation = Deprecation.create(deprecation)
58
+ @schema = schema
59
+ @shorthand = shorthand
60
+ @source = nil
61
+ @value = nil
62
+ @on_set = nil
63
+ bind_on_set(on_set) unless on_set.nil?
64
+ @types = nil
65
+ @values = nil
66
+ @kind = :other
67
+ allowed = infer_allowed_from_schema(schema, allowed) if schema
68
+ apply_allowed(allowed) unless allowed.nil?
69
+ end
70
+
71
+ # Set the `on_set` callback, called with the new value each time the value is set.
72
+ # Safe to call after construction: used by `Parser#on_set` for a target object created after declaration.
73
+ # The callback is called with the current value, if any.
74
+ # @param callback [#call] e.g. a `Method` or a lambda
75
+ # @return [nil]
76
+ def bind_on_set(callback)
77
+ Aspera.assert(callback.respond_to?(:call)) { "#{@option}: on_set callback must respond to call" }
78
+ @on_set = callback
79
+ Log.log.trace1 { "bind_on_set: #{@option}".green }
80
+ @on_set.call(@value) unless @value.nil?
81
+ nil
82
+ end
83
+
84
+ # @return [String] description of the option: explicit one, or first line of schema description
85
+ def description
86
+ return @description unless @description.nil?
87
+ return if @schema.nil?
88
+ schema_node = Schema::Registry.instance.reader(@schema).current
89
+ first_line = (schema_node['title'] || schema_node['description'].to_s).lines.first.to_s.strip
90
+ first_line.end_with?('.') ? first_line[0..-2] : first_line
91
+ end
92
+
93
+ # @return [String, nil] allowed values, or expected types when not plain `String`, e.g. `Hash|String`
94
+ def allowed_info
95
+ return @values.join('|') if @values&.any?
96
+ types = @types&.reject { |t| t.eql?(NilClass) }
97
+ return if types.nil? || types.empty? || types.eql?(Type::STRING)
98
+ types.map(&:name).join('|')
99
+ end
100
+
101
+ # @return [Boolean] `true` if option takes no value
102
+ def flag? = @kind.eql?(:flag)
103
+
104
+ # @param value [Object] value given to option
105
+ # @return [Boolean] `true` if value asks for the schema of option
106
+ def schema_request?(value) = value.eql?(SchemaRequest::KEYWORD) && @types&.include?(Hash)
107
+
108
+ # Reset stored value to nil
109
+ # @return [nil]
110
+ def clear
111
+ store(nil, nil)
112
+ end
113
+
114
+ # Get current option value
115
+ # @param log [Boolean] whether to log the value retrieval
116
+ # @return [Object] current value
117
+ def value(log: true)
118
+ Log.log.trace1 { "#{@option} -> (#{@value.class})#{@value}" } if log
119
+ @value
120
+ end
121
+
122
+ # Assign value to option.
123
+ # Value can be a `String`, then evaluated with `ExtendedValue`, or directly a value.
124
+ # `Hash` and `Array` values are merged with current value.
125
+ # @param value [String, Object] Value to assign to option
126
+ # @param source [Symbol] `OptionSource` of value
127
+ # @param warn_deprecation [Boolean] Emit deprecation warning (false for internal transfers)
128
+ # @param merge [Boolean] Merge `Hash` and `Array` with current value (false: value is already complete)
129
+ # @return [nil]
130
+ # @raise [SchemaRequest] if value is `help` and schema is known
131
+ def assign_value(value, source:, warn_deprecation: true, merge: true)
132
+ # Value from a source with lower priority than current value: only fills containers
133
+ lower = !@source.nil? && OptionSource.priority(source) < OptionSource.priority(@source)
134
+ if lower && ![Hash, Array].include?(@types&.first)
135
+ Log.log.debug { "#{source}: #{@option}: ignored, already set from #{@source}" }
136
+ return
137
+ end
138
+ Aspera.assert(!@deprecation, type: :warn) { "Option #{@option} is #{@deprecation}" } if warn_deprecation
139
+ if schema_request?(value)
140
+ return if lower
141
+ raise SchemaRequest.new(:option, @option, @schema) unless @schema.nil?
142
+ # Schema depends on command: kept as-is, raised by Parser#get_option(schema:)
143
+ store(value, source)
144
+ return
145
+ end
146
+ new_value = coerce(ExtendedValue.instance.evaluate(value, context: "option: #{@option}", allowed: @types))
147
+ new_value = {@shorthand => new_value} if @shorthand && new_value.is_a?(String)
148
+ Log.log.trace1 { "#{source}: #{@option} <- (#{new_value.class})#{new_value}" }
149
+ Aspera.assert_type(new_value, *@types, type: BadArgument) { "Option #{@option}" } if @types
150
+ if merge && (new_value.is_a?(Hash) || new_value.is_a?(Array))
151
+ current_value = @value
152
+ mergeable = current_value.is_a?(new_value.is_a?(Hash) ? Hash : Array) && !current_value.empty?
153
+ if lower
154
+ # Current value has priority: merge new value under it, unless explicitly emptied
155
+ return unless mergeable
156
+ new_value, current_value = current_value, new_value
157
+ source = @source
158
+ end
159
+ new_value = new_value.is_a?(Hash) ? current_value.deep_merge(new_value) : current_value + new_value if mergeable
160
+ end
161
+ validate_schema(new_value) unless %i[code default].include?(source)
162
+ store(new_value, source)
163
+ nil
164
+ end
165
+
166
+ private
167
+
168
+ # Validate a structured value against the schema of the option.
169
+ # Value may be partial: completed by other sources or defaults, so `required` is not enforced.
170
+ # @param value [Object] value to validate
171
+ # @raise [BadArgument] if value does not match schema
172
+ def validate_schema(value)
173
+ return unless @schema && (value.is_a?(Hash) || value.is_a?(Array))
174
+ errors = Schema::Validator.instance.errors(value, @schema, partial: true)
175
+ raise BadArgument, "Option #{@option}: #{errors.join('; ')} (use --#{@option.to_s.tr('_', '-')}=#{SchemaRequest::KEYWORD} for schema)" unless errors.empty?
176
+ end
177
+
178
+ # Derive the `allowed:` value from the schema when not explicitly provided.
179
+ # Returns `allowed` unchanged when the schema provides no usable type information.
180
+ # @param schema [String] schema identifier
181
+ # @param allowed [Object] caller-supplied allowed value (may be nil or Type::STRING)
182
+ # @return [Object] resolved allowed (Hash, Array, or the original value)
183
+ def infer_allowed_from_schema(schema, allowed)
184
+ return allowed unless allowed.nil? || allowed.eql?(Type::STRING)
185
+
186
+ schema_reader = Schema::Registry.instance.reader(schema) rescue nil
187
+ schema_node = schema_reader&.current
188
+ return allowed unless schema_node
189
+
190
+ case schema_node['type']
191
+ when 'object' then return Hash
192
+ when 'array' then return Array
193
+ end
194
+ # No top-level type: inspect oneOf/anyOf branches; if all resolve to 'object', infer Hash
195
+ composite_key = (%w[oneOf anyOf] & schema_node.keys).first
196
+ return allowed unless composite_key
197
+
198
+ branch_types = schema_node[composite_key].map do |branch|
199
+ resolved = branch['$ref'] ? schema_reader.resolve_ref(branch['$ref']).current : branch
200
+ resolved['type']
201
+ end
202
+ if branch_types.all?('object')
203
+ Hash
204
+ else
205
+ Aspera.assert(
206
+ !allowed.nil? && !allowed.eql?(Type::STRING),
207
+ "option :#{@option}: schema '#{schema}' has mixed-type oneOf branches #{branch_types.uniq}: specify allowed: explicitly"
208
+ )
209
+ allowed
210
+ end
211
+ end
212
+
213
+ # Initialize @types, @values and @kind from the resolved `allowed` specifier.
214
+ # @param allowed [Class, Array<Class>, Array<Symbol>] resolved allowed value (never nil)
215
+ def apply_allowed(allowed)
216
+ allowed = [allowed] if allowed.is_a?(Class)
217
+ Aspera.assert_type(allowed, Array)
218
+ if allowed.eql?(Type::NONE)
219
+ @kind = :flag
220
+ @types = Type::NONE
221
+ elsif allowed.take(Type::SYMBOL_ARRAY.length) == Type::SYMBOL_ARRAY
222
+ # Array of defined symbol values
223
+ @kind = :enum_list
224
+ @types = Type::SYMBOL_ARRAY
225
+ @values = allowed[Type::SYMBOL_ARRAY.length..]
226
+ elsif allowed.all?(Symbol)
227
+ @kind = :enum
228
+ @types = Type::ENUM
229
+ @values = allowed
230
+ elsif allowed.all?(Class)
231
+ @types = allowed
232
+ @kind =
233
+ if allowed.sort_by(&:name).eql?(Type::BOOLEAN) then :boolean
234
+ elsif allowed.eql?(Type::INTEGER) then :integer
235
+ elsif allowed.eql?(Type::STRING_ARRAY) then :string_list
236
+ else :other
237
+ end
238
+ @values = BoolValue::ALL if @kind.eql?(:boolean)
239
+ else
240
+ Aspera.error_unexpected_value(allowed)
241
+ end
242
+ # Containers start empty, unless nil is allowed
243
+ default = {Array => [], Hash => {}}[@types.first]
244
+ store(default, :default) if !default.nil? && !@types.include?(NilClass) && @value.nil?
245
+ end
246
+
247
+ # Convert value from command line, env or preset (String) to the type of option
248
+ # @param value [Object] evaluated value
249
+ # @return [Object] converted value
250
+ def coerce(value)
251
+ case @kind
252
+ when :enum
253
+ # Boolean from dot-path value, e.g. `no` for `%i[no header read]`
254
+ value = (value ? BoolValue::YES_SYM : BoolValue::NO_SYM).to_s if BoolValue::TYPES.include?(value.class)
255
+ value.is_a?(String) ? Parser.get_from_list(value, @option, @values) : value
256
+ when :boolean
257
+ BoolValue.true?(value.is_a?(String) ? Parser.get_from_list(value, @option, BoolValue::ALL) : value)
258
+ when :integer
259
+ value.nil? ? value : Integer(value)
260
+ when :string_list
261
+ value.is_a?(String) ? [value] : value
262
+ when :enum_list
263
+ value = [value] if value.is_a?(String)
264
+ Aspera.assert_array_all(value, String, type: BadArgument)
265
+ value.map { |v| Parser.get_from_list(v, @option, @values) }
266
+ else
267
+ # nil on a Hash/Array option resets to empty container
268
+ value.nil? && [Hash, Array].include?(@types&.first) ? @types.first.new : value
269
+ end
270
+ end
271
+
272
+ # @param new_value [Object] value to store
273
+ # @param source [Symbol, nil] `OptionSource` of value
274
+ def store(new_value, source)
275
+ @value = new_value
276
+ @source = source
277
+ @on_set&.call(new_value)
278
+ end
279
+ end
280
+ end
281
+ end
@@ -323,7 +323,7 @@ components:
323
323
  HTTP/S connection parameters for REST calls (not `ascp` WSS).
324
324
 
325
325
  Keys are dispatched at startup to three targets:
326
- `RestParameters` (`user_agent`, `download_partial_suffix`, `retry_*`),
326
+ `Rest::Parameters` (`user_agent`, `download_partial_suffix`, `retry_*`),
327
327
  `SSL` (`ssl_options`), and `OAuth` (`token_cache_max_age`, `token_refresh_threshold`).
328
328
  Any remaining key is forwarded as a setter to the `Net::HTTP` session
329
329
  (e.g. `ca_file`, `verify_mode`) — the list below covers the common ones.
@@ -661,15 +661,38 @@ components:
661
661
  Value sent in the `x-instana-host` header.
662
662
  Defaults to the local machine's hostname.
663
663
  example: hsts-prod-01
664
+ OrchestratorWorkflowStart:
665
+ type: object
666
+ description: >-
667
+ Execution of the work order created by `orchestrator workflows start`.
668
+ By default, the call is asynchronous and returns the work order information.
669
+ A synchronous call returns the value of the output variable, if specified.
670
+ additionalProperties: false
671
+ properties:
672
+ synchronous:
673
+ type: boolean
674
+ description: Wait for completion of the work order.
675
+ default: false
676
+ step:
677
+ type: string
678
+ description: >-
679
+ Name of the work step providing the result.
680
+ Requires `variable`, and implies `synchronous`.
681
+ example: ResultStep
682
+ variable:
683
+ type: string
684
+ description: >-
685
+ Name of the output variable of `step` returned as result.
686
+ Requires `step`, and implies `synchronous`.
687
+ example: Complete_status_message
664
688
  TableOptions:
665
689
  type: object
666
690
  description: Terminal table rendering options.
667
691
  properties:
668
692
  pivot:
669
- type: string
670
- description: Control how an object list is displayed (no/yes/single).
671
- enum: ['no', 'yes', 'single']
672
- default: 'no'
693
+ description: Control how an object list is displayed (false/true/single).
694
+ enum: [false, true, single]
695
+ default: false
673
696
  OutOptions:
674
697
  type: object
675
698
  description: Output rendering options (dot-notation sub-properties).
@@ -705,5 +728,15 @@ components:
705
728
  type: boolean
706
729
  description: Show secrets in command output.
707
730
  default: false
731
+ colors:
732
+ type: boolean
733
+ description: >-
734
+ Use ANSI colors and styles in terminal output and logs.
735
+ Default is auto-detected: enabled if both stdout and stderr are terminals and `TERM` is not `dumb`, or if `CLICOLOR_FORCE=1`.
736
+ utf8:
737
+ type: boolean
738
+ description: >-
739
+ Use Unicode characters in terminal output (e.g. table borders, check marks).
740
+ Default is auto-detected: enabled if stdout is a terminal and the locale is UTF-8.
708
741
  img:
709
742
  $ref: "#/components/schemas/ImageOptions"