aspera-cli 4.27.5 → 4.28.0

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 (139) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +160 -4
  4. data/CONTRIBUTING.md +4 -2
  5. data/README.md +1 -1
  6. data/bin/asession +1 -1
  7. data/docs/README.md +1086 -331
  8. data/docs/test-mcp-with-ai.md +5 -3
  9. data/lib/aspera/agent/direct.rb +15 -4
  10. data/lib/aspera/agent/factory.rb +2 -1
  11. data/lib/aspera/agent/node.rb +1 -1
  12. data/lib/aspera/api/cos_node.rb +1 -1
  13. data/lib/aspera/api/faspex.rb +1 -1
  14. data/lib/aspera/api/node.rb +6 -2
  15. data/lib/aspera/ascp/installation.rb +47 -11
  16. data/lib/aspera/ascp/management.rb +89 -43
  17. data/lib/aspera/cli/ascp_actions.rb +5 -19
  18. data/lib/aspera/cli/bootstrapper.rb +1 -2
  19. data/lib/aspera/cli/command_registry.rb +43 -3
  20. data/lib/aspera/cli/command_spec.rb +3 -0
  21. data/lib/aspera/cli/completion/ascli.bash +39 -5
  22. data/lib/aspera/cli/completion/ascli.fish +16 -8
  23. data/lib/aspera/cli/completion/ascli.ps1 +41 -0
  24. data/lib/aspera/cli/completion/ascli.zsh +20 -4
  25. data/lib/aspera/cli/completion_actions.rb +360 -0
  26. data/lib/aspera/cli/error.rb +42 -0
  27. data/lib/aspera/cli/extended_value.rb +30 -5
  28. data/lib/aspera/cli/formatter.rb +118 -56
  29. data/lib/aspera/cli/hints.rb +0 -1
  30. data/lib/aspera/cli/http.rb +6 -5
  31. data/lib/aspera/cli/info.rb +10 -4
  32. data/lib/aspera/cli/mailer.rb +1 -1
  33. data/lib/aspera/cli/mcp/http_servlet.rb +156 -0
  34. data/lib/aspera/cli/mcp/secrets.rb +143 -0
  35. data/lib/aspera/cli/mcp/tool.rb +231 -0
  36. data/lib/aspera/cli/option_value.rb +9 -1
  37. data/lib/aspera/cli/options.schema.yaml +390 -39
  38. data/lib/aspera/cli/parser.rb +14 -5
  39. data/lib/aspera/cli/plugins/aoc.rb +8 -11
  40. data/lib/aspera/cli/plugins/base.rb +36 -15
  41. data/lib/aspera/cli/plugins/config.rb +15 -44
  42. data/lib/aspera/cli/plugins/console.rb +3 -1
  43. data/lib/aspera/cli/plugins/factory.rb +1 -1
  44. data/lib/aspera/cli/plugins/faspex5.rb +9 -19
  45. data/lib/aspera/cli/plugins/faspio.rb +36 -5
  46. data/lib/aspera/cli/plugins/httpgw.rb +1 -0
  47. data/lib/aspera/cli/plugins/mcp.rb +177 -118
  48. data/lib/aspera/cli/plugins/node.rb +14 -8
  49. data/lib/aspera/cli/plugins/orchestrator.rb +351 -38
  50. data/lib/aspera/cli/plugins/server.rb +3 -1
  51. data/lib/aspera/cli/plugins/shares.rb +205 -35
  52. data/lib/aspera/cli/preset_actions.rb +15 -7
  53. data/lib/aspera/cli/preset_manager.rb +24 -2
  54. data/lib/aspera/cli/prompt.rb +3 -1
  55. data/lib/aspera/cli/result.rb +17 -4
  56. data/lib/aspera/cli/runner.rb +133 -43
  57. data/lib/aspera/cli/security.rb +134 -0
  58. data/lib/aspera/cli/table_fitter.rb +116 -0
  59. data/lib/aspera/cli/terminal_formatter.rb +23 -34
  60. data/lib/aspera/cli/transfer_agent.rb +4 -1
  61. data/lib/aspera/cli/vault_manager.rb +6 -5
  62. data/lib/aspera/cli/version.rb +1 -1
  63. data/lib/aspera/cli/web_secret.html.erb +61 -0
  64. data/lib/aspera/cli/web_secret.rb +220 -0
  65. data/lib/aspera/cli/wizard.rb +19 -9
  66. data/lib/aspera/command_line_builder.rb +26 -0
  67. data/lib/aspera/data_repository.rb +38 -24
  68. data/lib/aspera/duration.rb +42 -0
  69. data/lib/aspera/environment.rb +88 -24
  70. data/lib/aspera/exec_spec.rb +6 -5
  71. data/lib/aspera/faspex_gw.rb +98 -32
  72. data/lib/aspera/faspex_postproc.rb +187 -44
  73. data/lib/aspera/formatter_interface.rb +0 -1
  74. data/lib/aspera/id_generator.rb +2 -1
  75. data/lib/aspera/json_rpc/client.rb +51 -32
  76. data/lib/aspera/json_rpc/version.rb +1 -0
  77. data/lib/aspera/keychain/base.rb +5 -0
  78. data/lib/aspera/keychain/encrypted_hash.rb +6 -2
  79. data/lib/aspera/keychain/factory.rb +2 -3
  80. data/lib/aspera/keychain/hashicorp_vault.rb +7 -4
  81. data/lib/aspera/keychain/macos_security.rb +119 -13
  82. data/lib/aspera/keychain/one_password_api.rb +8 -3
  83. data/lib/aspera/keychain/one_password_base.rb +14 -9
  84. data/lib/aspera/keychain/one_password_cli.rb +4 -2
  85. data/lib/aspera/log.rb +3 -6
  86. data/lib/aspera/markdown.rb +152 -115
  87. data/lib/aspera/mime.rb +6 -0
  88. data/lib/aspera/nagios.rb +3 -1
  89. data/lib/aspera/node_emulator.rb +98 -101
  90. data/lib/aspera/oauth/{base.rb → client/base.rb} +5 -4
  91. data/lib/aspera/oauth/{boot.rb → client/boot.rb} +3 -2
  92. data/lib/aspera/oauth/{factory.rb → client/factory.rb} +7 -0
  93. data/lib/aspera/oauth/{generic.rb → client/generic.rb} +1 -1
  94. data/lib/aspera/oauth/{json_credentials.rb → client/json_credentials.rb} +1 -1
  95. data/lib/aspera/oauth/{jwt.rb → client/jwt.rb} +1 -1
  96. data/lib/aspera/oauth/{url_json.rb → client/url_json.rb} +1 -1
  97. data/lib/aspera/oauth/{web.rb → client/web.rb} +2 -2
  98. data/lib/aspera/oauth/server/authorize.html.erb +34 -0
  99. data/lib/aspera/oauth/server/pkce.rb +426 -0
  100. data/lib/aspera/orchestrator_workflow_checker.rb +561 -0
  101. data/lib/aspera/preview/terminal.rb +3 -2
  102. data/lib/aspera/rainbow.rb +27 -1
  103. data/lib/aspera/rest/aspera_errors.rb +51 -59
  104. data/lib/aspera/rest/client.rb +21 -14
  105. data/lib/aspera/rest/error_analyzer.rb +9 -0
  106. data/lib/aspera/rest/list.rb +6 -6
  107. data/lib/aspera/rest/util.rb +7 -1
  108. data/lib/aspera/rest.rb +0 -1
  109. data/lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml +0 -2
  110. data/lib/aspera/schema/IBM Aspera Orchestrator API-v1-enhanced.yaml +4001 -0
  111. data/lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0-enhanced.yaml +1097 -0
  112. data/lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml +35 -35
  113. data/lib/aspera/schema/IBM_Aspera_Shares.yaml +819 -7
  114. data/lib/aspera/schema/documentation.rb +50 -78
  115. data/lib/aspera/schema/reader.rb +39 -11
  116. data/lib/aspera/schema/registry.rb +8 -2
  117. data/lib/aspera/secret_hider.rb +94 -15
  118. data/lib/aspera/secret_strength.rb +114 -0
  119. data/lib/aspera/servlet_helpers.rb +111 -0
  120. data/lib/aspera/sync/args.schema.yaml +3 -1
  121. data/lib/aspera/sync/conf.schema.yaml +16 -6
  122. data/lib/aspera/sync/operations.rb +21 -1
  123. data/lib/aspera/temp_file_manager.rb +79 -20
  124. data/lib/aspera/transfer/parameters.rb +5 -0
  125. data/lib/aspera/transfer/spec.rb +52 -12
  126. data/lib/aspera/transfer/spec.schema.yaml +8 -5
  127. data/lib/aspera/web_auth/index.html.erb +16 -0
  128. data/lib/aspera/web_auth/server.rb +18 -10
  129. data/lib/aspera/web_page.html.erb +262 -0
  130. data/lib/aspera/web_page.rb +61 -0
  131. data/lib/aspera/web_server_simple.rb +76 -10
  132. data.tar.gz.sig +0 -0
  133. metadata +47 -32
  134. metadata.gz.sig +0 -0
  135. data/lib/aspera/cli/mcp_tool.rb +0 -189
  136. data/lib/aspera/oauth.rb +0 -9
  137. data/lib/aspera/schema/IBM Aspera Orchestrator API-v1.yaml +0 -1784
  138. data/lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0.yaml +0 -249
  139. data/lib/aspera/web_auth/index.html +0 -147
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aspera-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.27.5
4
+ version: 4.28.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent Martin
@@ -39,19 +39,19 @@ cert_chain:
39
39
  date: 1980-01-02 00:00:00.000000000 Z
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
42
- name: blankslate
42
+ name: base64
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '3.1'
47
+ version: '0.3'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '3.1'
54
+ version: '0.3'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: chunky_png
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '2.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: jmespath
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.6'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.6'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: json_schemer
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -290,20 +304,6 @@ dependencies:
290
304
  - - "~>"
291
305
  - !ruby/object:Gem::Version
292
306
  version: '1.2'
293
- - !ruby/object:Gem::Dependency
294
- name: word_wrap
295
- requirement: !ruby/object:Gem::Requirement
296
- requirements:
297
- - - "~>"
298
- - !ruby/object:Gem::Version
299
- version: '1.0'
300
- type: :runtime
301
- prerelease: false
302
- version_requirements: !ruby/object:Gem::Requirement
303
- requirements:
304
- - - "~>"
305
- - !ruby/object:Gem::Version
306
- version: '1.0'
307
307
  - !ruby/object:Gem::Dependency
308
308
  name: xml-simple
309
309
  requirement: !ruby/object:Gem::Requirement
@@ -365,7 +365,9 @@ files:
365
365
  - lib/aspera/cli/command_spec.rb
366
366
  - lib/aspera/cli/completion/ascli.bash
367
367
  - lib/aspera/cli/completion/ascli.fish
368
+ - lib/aspera/cli/completion/ascli.ps1
368
369
  - lib/aspera/cli/completion/ascli.zsh
370
+ - lib/aspera/cli/completion_actions.rb
369
371
  - lib/aspera/cli/context.rb
370
372
  - lib/aspera/cli/deprecation.rb
371
373
  - lib/aspera/cli/error.rb
@@ -376,7 +378,9 @@ files:
376
378
  - lib/aspera/cli/http.rb
377
379
  - lib/aspera/cli/info.rb
378
380
  - lib/aspera/cli/mailer.rb
379
- - lib/aspera/cli/mcp_tool.rb
381
+ - lib/aspera/cli/mcp/http_servlet.rb
382
+ - lib/aspera/cli/mcp/secrets.rb
383
+ - lib/aspera/cli/mcp/tool.rb
380
384
  - lib/aspera/cli/option_declarator.rb
381
385
  - lib/aspera/cli/option_registry.rb
382
386
  - lib/aspera/cli/option_types.rb
@@ -408,14 +412,18 @@ files:
408
412
  - lib/aspera/cli/result.rb
409
413
  - lib/aspera/cli/runner.rb
410
414
  - lib/aspera/cli/secret_finder.rb
415
+ - lib/aspera/cli/security.rb
411
416
  - lib/aspera/cli/special_values.rb
412
417
  - lib/aspera/cli/sync_actions.rb
418
+ - lib/aspera/cli/table_fitter.rb
413
419
  - lib/aspera/cli/terminal_formatter.rb
414
420
  - lib/aspera/cli/transfer_actions.rb
415
421
  - lib/aspera/cli/transfer_agent.rb
416
422
  - lib/aspera/cli/transfer_progress.rb
417
423
  - lib/aspera/cli/vault_manager.rb
418
424
  - lib/aspera/cli/version.rb
425
+ - lib/aspera/cli/web_secret.html.erb
426
+ - lib/aspera/cli/web_secret.rb
419
427
  - lib/aspera/cli/wizard.rb
420
428
  - lib/aspera/command_line_builder.rb
421
429
  - lib/aspera/command_line_converter.rb
@@ -428,6 +436,7 @@ files:
428
436
  - lib/aspera/data/6
429
437
  - lib/aspera/data_repository.rb
430
438
  - lib/aspera/dot_container.rb
439
+ - lib/aspera/duration.rb
431
440
  - lib/aspera/environment.rb
432
441
  - lib/aspera/exec_spec.rb
433
442
  - lib/aspera/faspex_gw.rb
@@ -453,15 +462,17 @@ files:
453
462
  - lib/aspera/mime.rb
454
463
  - lib/aspera/nagios.rb
455
464
  - lib/aspera/node_emulator.rb
456
- - lib/aspera/oauth.rb
457
- - lib/aspera/oauth/base.rb
458
- - lib/aspera/oauth/boot.rb
459
- - lib/aspera/oauth/factory.rb
460
- - lib/aspera/oauth/generic.rb
461
- - lib/aspera/oauth/json_credentials.rb
462
- - lib/aspera/oauth/jwt.rb
463
- - lib/aspera/oauth/url_json.rb
464
- - lib/aspera/oauth/web.rb
465
+ - lib/aspera/oauth/client/base.rb
466
+ - lib/aspera/oauth/client/boot.rb
467
+ - lib/aspera/oauth/client/factory.rb
468
+ - lib/aspera/oauth/client/generic.rb
469
+ - lib/aspera/oauth/client/json_credentials.rb
470
+ - lib/aspera/oauth/client/jwt.rb
471
+ - lib/aspera/oauth/client/url_json.rb
472
+ - lib/aspera/oauth/client/web.rb
473
+ - lib/aspera/oauth/server/authorize.html.erb
474
+ - lib/aspera/oauth/server/pkce.rb
475
+ - lib/aspera/orchestrator_workflow_checker.rb
465
476
  - lib/aspera/persistency_action_once.rb
466
477
  - lib/aspera/persistency_folder.rb
467
478
  - lib/aspera/preview/file_types.rb
@@ -489,8 +500,8 @@ files:
489
500
  - lib/aspera/schema/IBM Aspera Console-enhanced.yaml
490
501
  - lib/aspera/schema/IBM Aspera Faspex API-5.0-enhanced.yaml
491
502
  - lib/aspera/schema/IBM Aspera Node API-4.4.6.yaml
492
- - lib/aspera/schema/IBM Aspera Orchestrator API-v1.yaml
493
- - lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0.yaml
503
+ - lib/aspera/schema/IBM Aspera Orchestrator API-v1-enhanced.yaml
504
+ - lib/aspera/schema/IBM Aspera faspio Gateway API-1.0.0-enhanced.yaml
494
505
  - lib/aspera/schema/IBM Aspera on Cloud API-0.2.6-enhanced.yaml
495
506
  - lib/aspera/schema/IBM Aspera on Cloud Automation API-1.0.5-enhanced.yaml
496
507
  - lib/aspera/schema/IBM_Aspera_Shares.yaml
@@ -500,6 +511,8 @@ files:
500
511
  - lib/aspera/schema/registry.rb
501
512
  - lib/aspera/schema/validator.rb
502
513
  - lib/aspera/secret_hider.rb
514
+ - lib/aspera/secret_strength.rb
515
+ - lib/aspera/servlet_helpers.rb
503
516
  - lib/aspera/ssh.rb
504
517
  - lib/aspera/ssl.rb
505
518
  - lib/aspera/string_ext.rb
@@ -517,8 +530,10 @@ files:
517
530
  - lib/aspera/transfer/spec.rb
518
531
  - lib/aspera/transfer/spec.schema.yaml
519
532
  - lib/aspera/uri_reader.rb
520
- - lib/aspera/web_auth/index.html
533
+ - lib/aspera/web_auth/index.html.erb
521
534
  - lib/aspera/web_auth/server.rb
535
+ - lib/aspera/web_page.html.erb
536
+ - lib/aspera/web_page.rb
522
537
  - lib/aspera/web_server_simple.rb
523
538
  - lib/aspera/yaml.rb
524
539
  - lib/transferd_pb.rb
@@ -540,7 +555,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
540
555
  requirements:
541
556
  - - ">="
542
557
  - !ruby/object:Gem::Version
543
- version: '3.1'
558
+ version: '3.2'
544
559
  required_rubygems_version: !ruby/object:Gem::Requirement
545
560
  requirements:
546
561
  - - ">="
metadata.gz.sig CHANGED
Binary file
@@ -1,189 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # cspell:ignore ascli
4
-
5
- require 'json'
6
- require 'aspera/log'
7
- require 'aspera/secret_hider'
8
- require 'aspera/cli/runner'
9
- require 'aspera/cli/error'
10
- require 'aspera/schema/reader'
11
- require 'aspera/schema/registry'
12
- unless defined?(MCP::Tool)
13
- begin
14
- require 'mcp'
15
- rescue LoadError
16
- raise Cli::Error, "The 'mcp' and 'rack' gems are required. Install them with: gem install mcp rack"
17
- end
18
- end
19
-
20
- module Aspera
21
- module Cli
22
- # MCP Tool: executes an ascli command in-process.
23
- class McpTool < MCP::Tool
24
- # Default maximum byte size of the JSON text content returned for list results.
25
- # Items are appended whole until the limit is reached; the full list is always
26
- # available in structuredContent.
27
- DEFAULT_MAX_TEXT_BYTES = 100_000
28
- # Default extra arguments automatically prepended to every ascli call.
29
- # Keeps the AI from having to remember mandatory flags on every invocation.
30
- DEFAULT_EXTRA_ARGS = ['--interactive=no', '--transfer.asynchronous=true'].freeze
31
-
32
- tool_name 'execute_ascli_command'
33
-
34
- description <<~DESC.strip
35
- Execute any ascli (Aspera CLI) command in-process and return its result.
36
-
37
- SYNTAX
38
- args is a JSON array of strings mirroring the CLI command line.
39
- Element 0 : plugin name (aoc, faspex5, node, server, config, …).
40
- Elements 1+: sub-commands, positional arguments, and --option=value flags in any order.
41
- Structured values use an extended-value prefix on the relevant element:
42
- "@json:{...}" — inline JSON object or array (preferred: no shell quoting)
43
- "@preset:name" — expand a saved preset
44
- "@env:VAR" — read value from environment variable
45
- "@file:/path" — read value from a file
46
-
47
- AUTOMATIC FLAGS
48
- The server prepends extra_args to every call (default: #{DEFAULT_EXTRA_ARGS.join(' ')}).
49
- Do NOT repeat them. To override one, include it in args: later values take precedence.
50
- Commands never prompt: if credentials are missing, an error is returned; report it and stop.
51
-
52
- DISCOVERY — never guess command or field names from training data
53
- Step 1 — commands of a plugin, with syntax:
54
- ["config", "commands", "<plugin>"]
55
- Returns { syntax, description } for every command of that plugin.
56
- Notation: <arg> mandatory, [<arg>] optional, <a|b> enum, <arg...> variadic, <arg:Hash> typed.
57
- A line ending with <command...> and "(see: <plugin> <path>)" provides the commands of that path:
58
- list them with ["config", "commands", "<plugin>", "<command>", ...] (command words only).
59
- Omit <plugin> to list the commands of all plugins (large).
60
- Step 2 — schema of a Hash argument (shown <name:Hash>), MANDATORY before calling such a command:
61
- ["<plugin>", "<cmd>", ..., "help"]
62
- Put the literal "help" in place of the Hash argument. Returns field names, types,
63
- required flags and descriptions. Never infer fields from server error messages.
64
- Step 2b — filter parameters of a list command:
65
- ["<plugin>", "<cmd>", ..., "--query=help"]
66
- Step 3 — all --flags of a plugin, with allowed values:
67
- ["config", "options", "<plugin>"]
68
- Documentation:
69
- ["config", "documentation", "toc"] → { level, title, anchor } per heading
70
- ["config", "documentation", "local", "<anchor>"] → one README section
71
- Presets (saved credentials):
72
- ["config", "preset", "overview"]
73
-
74
- RESULT FORMAT
75
- Structured data is always in structuredContent (a JSON object; lists are under "items").
76
- For lists, text content is limited to #{DEFAULT_MAX_TEXT_BYTES} bytes (whole items only);
77
- when truncated, a WARNING line gives the real total. Read structuredContent.items for
78
- the full dataset — never report counts or search results from a truncated text block.
79
-
80
- FILE LIST FOR TRANSFERS
81
- For all transfers (upload, download, package send, …), append source paths at the
82
- end of args — no --sources flag needed.
83
-
84
- EXAMPLES
85
- ["config", "commands", "aoc"]
86
- ["aoc", "admin", "user", "create", "help"]
87
- ["config", "options", "aoc"]
88
- ["config", "documentation", "local", "leveraging-ai-assistance"]
89
- ["aoc", "--preset=myaoc", "packages", "list"]
90
- ["aoc", "--preset=myaoc", "admin", "user", "create", '@json:{"email":"a@b.com","name":"Alice"}']
91
- ["aoc", "--preset=myaoc", "packages", "send",
92
- '@json:{"name":"pkg","recipients":["user@example.com"]}', "/local/a.txt", "/local/b.txt"]
93
- ["server", "--preset=myserver", "upload", "--to-folder=/uploads", "/local/a.txt"]
94
- ["server", "browse", "/", "--url=ssh://host:33001", "--username=user", "--password=secret"]
95
- DESC
96
-
97
- input_schema(
98
- properties: {
99
- args: {
100
- type: 'array',
101
- items: {type: 'string'},
102
- minItems: 1,
103
- description: 'ascli arguments: first element is the plugin name, followed by action and --option=value flags'
104
- }
105
- },
106
- required: ['args']
107
- )
108
-
109
- class << self
110
- attr_accessor :max_text_bytes, :extra_args
111
-
112
- def call(args:, server_context: nil)
113
- effective_args = Array(extra_args || DEFAULT_EXTRA_ARGS) + args
114
- Log.dump(:mcp_execute, effective_args)
115
- runner = Runner.new(effective_args)
116
- result = runner.run_with_result
117
- case result
118
- when Result::Nothing, Result::Empty, NilClass
119
- MCP::Tool::Response.new([{type: 'text', text: ''}])
120
- when Result::SingleObject, Result::ObjectList, Result::ValueList
121
- # Secrets never reach the AI client, whatever the output format requested in args.
122
- SecretHider.instance.deep_remove_secret(result.data)
123
- # Apply --select filter in place (affects both text and structuredContent).
124
- runner.context.formatter.filter_columns_on_select(result.data) if result.data.is_a?(Array)
125
- # MCP spec requires structuredContent to be a JSON object (not an array).
126
- structured = result.data.is_a?(Array) ? {items: result.data} : result.data
127
- content = if result.data.is_a?(Array)
128
- text_limit = max_text_bytes || DEFAULT_MAX_TEXT_BYTES
129
- truncated_items = truncate_items_by_bytes(result.data, text_limit)
130
- total = result.data.size
131
- if truncated_items.size < total
132
- [
133
- {type: 'text', text: JSON.generate(truncated_items)},
134
- {type: 'text', text: "WARNING: result truncated to #{truncated_items.size} of #{total} items. Full dataset available in structuredContent."}
135
- ]
136
- else
137
- [{type: 'text', text: JSON.generate(result.data)}]
138
- end
139
- else
140
- [{type: 'text', text: JSON.generate(result.data)}]
141
- end
142
- MCP::Tool::Response.new(content, structured_content: structured)
143
- else
144
- MCP::Tool::Response.new([{type: 'text', text: SecretHider.instance.hide_secrets_in_string(result.data.to_s, all: true)}])
145
- end
146
- rescue Cli::SchemaRequest => e
147
- schema_path = e.path
148
- if schema_path.nil?
149
- MCP::Tool::Response.new([{type: 'text', text: "#{e.class}: #{e.message} (no schema available)"}], error: true)
150
- else
151
- rows = schema_to_rows(Schema::Registry.instance.reader(schema_path))
152
- structured = {items: rows}
153
- MCP::Tool::Response.new([{type: 'text', text: JSON.generate(rows)}], structured_content: structured)
154
- end
155
- rescue SystemExit => e
156
- MCP::Tool::Response.new([{type: 'text', text: "exited with status #{e.status}"}], error: !e.status.zero?)
157
- rescue => e
158
- MCP::Tool::Response.new([{type: 'text', text: "#{e.class}: #{dedupe_lines(e.message)}"}], error: true)
159
- end
160
-
161
- # Delegate to Schema::Reader#to_rows — semantic fields, no ANSI, MCP/JSON-ready.
162
- def schema_to_rows(reader)
163
- reader.to_rows
164
- end
165
-
166
- # Collapse consecutive duplicate lines in a multi-line message.
167
- # Each run of identical lines is replaced by one line + "(×N)" suffix when N > 1.
168
- def dedupe_lines(msg)
169
- return msg unless msg.include?("\n")
170
- msg.split("\n").chunk_while { |a, b| a == b }.map do |group|
171
- group.size > 1 ? "#{group.first} (x#{group.size})" : group.first
172
- end.join("\n")
173
- end
174
-
175
- # Returns the largest prefix of `items` whose JSON serialization fits within `max_bytes`.
176
- # Items are appended whole — no item is ever split mid-JSON.
177
- def truncate_items_by_bytes(items, max_bytes)
178
- buf = +''
179
- items.each_with_index do |item, i|
180
- fragment = (i.zero? ? '[' : ',') + JSON.generate(item)
181
- break if buf.bytesize + fragment.bytesize + 1 > max_bytes # +1 for closing ']'
182
- buf << fragment
183
- end
184
- buf.empty? ? [] : JSON.parse("#{buf}]")
185
- end
186
- end
187
- end
188
- end
189
- end
data/lib/aspera/oauth.rb DELETED
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'aspera/oauth/factory'
4
- require 'aspera/oauth/boot'
5
- require 'aspera/oauth/generic'
6
- require 'aspera/oauth/jwt'
7
- require 'aspera/oauth/web'
8
- require 'aspera/oauth/url_json'
9
- require 'aspera/oauth/json_credentials'