mj 0.6.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f73fffd1a785c75120ffed30d970ffbc9d64f525a5a5729c814a785f7c0868e
4
- data.tar.gz: 8a09ecd20bb4bae4e54f07d30f09c9fa534b4d2c6090d87353c3297cb1bb2210
3
+ metadata.gz: 8b15f4c4efd81a03bf545e20a2bebb6beff7a12612c470173073f35c5b67cab2
4
+ data.tar.gz: 6c61d4acd6cc0d8590835bfd038fe0e291df05fd3100db7fff41f189eeade3fe
5
5
  SHA512:
6
- metadata.gz: 90f2712ab6a67d83f45ce62f4a4213e0b85404ead8f218263771095ef09121dcaf29732e81a17e459be7d2788bb836f172ec34bb6d90e3e697f49599075378eb
7
- data.tar.gz: d05317d65dd3fb88eb5379f3e0e4439a2264c5b40d6a2276fec219058668748f852ea4474468fc7a56f527357ea5b8808d15a541bbb9558203ca6602edaec50e
6
+ metadata.gz: 7d1017ad9f4b623c86d864e16c5110b9ecc1e131bbe96e27f23e0782b79ce209257972837a857a6557877a484dd0de834c2bf0c5be6c38d2ff5c67866243872c
7
+ data.tar.gz: 77da1cdfb825c43e50d8ae4cf7b203f585fc7c4be33c1121ad47e46c30befe773ec9cfe345a980112e02b625e0f3a82bd4158ef5d15438e8f46f46816b416529
data/Gemfile CHANGED
@@ -16,3 +16,4 @@ gem "rubocop-rake"
16
16
  gem "rubocop-rspec"
17
17
  gem "simplecov", require: false
18
18
  gem "simplecov-lcov", require: false
19
+ gem "uri", "~> 0.13"
data/Gemfile.lock CHANGED
@@ -1,62 +1,103 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- mj (0.6.2)
4
+ mj (0.8.0)
5
+ koine-rest_client
6
+ mj-hash_utils
7
+ ruby-openai (~> 6.2.0)
5
8
  thor (~> 1.2.1)
6
9
 
7
10
  GEM
8
11
  remote: https://rubygems.org/
9
12
  specs:
13
+ addressable (2.8.6)
14
+ public_suffix (>= 2.0.2, < 6.0)
10
15
  ast (2.4.2)
11
16
  awesome_print (1.9.2)
12
17
  coderay (1.1.3)
13
- diff-lcs (1.5.0)
18
+ diff-lcs (1.5.1)
14
19
  docile (1.4.0)
20
+ event_stream_parser (0.3.0)
21
+ faraday (2.9.0)
22
+ faraday-net_http (>= 2.0, < 3.2)
23
+ faraday-multipart (1.0.4)
24
+ multipart-post (~> 2)
25
+ faraday-net_http (3.1.0)
26
+ net-http
27
+ httparty (0.21.0)
28
+ mini_mime (>= 1.0.0)
29
+ multi_xml (>= 0.5.2)
30
+ json (2.7.1)
31
+ koine-rest_client (1.1.1)
32
+ addressable (>= 2.3)
33
+ httparty (>= 0.17.0)
15
34
  koine-test_runner (0.4.0)
35
+ language_server-protocol (3.17.0.3)
16
36
  method_source (1.0.0)
17
- parallel (1.21.0)
18
- parser (3.1.1.0)
37
+ mini_mime (1.1.5)
38
+ mj-hash_utils (0.1.0)
39
+ multi_xml (0.6.0)
40
+ multipart-post (2.4.0)
41
+ net-http (0.4.1)
42
+ uri
43
+ parallel (1.24.0)
44
+ parser (3.3.0.5)
19
45
  ast (~> 2.4.1)
46
+ racc
20
47
  pry (0.14.2)
21
48
  coderay (~> 1.1)
22
49
  method_source (~> 1.0)
50
+ public_suffix (5.0.4)
51
+ racc (1.7.3)
23
52
  rainbow (3.1.1)
24
- rake (13.0.6)
25
- regexp_parser (2.2.1)
26
- rexml (3.2.5)
27
- rspec (3.11.0)
28
- rspec-core (~> 3.11.0)
29
- rspec-expectations (~> 3.11.0)
30
- rspec-mocks (~> 3.11.0)
31
- rspec-core (3.11.0)
32
- rspec-support (~> 3.11.0)
33
- rspec-expectations (3.11.0)
53
+ rake (13.1.0)
54
+ regexp_parser (2.9.0)
55
+ rexml (3.2.6)
56
+ rspec (3.13.0)
57
+ rspec-core (~> 3.13.0)
58
+ rspec-expectations (~> 3.13.0)
59
+ rspec-mocks (~> 3.13.0)
60
+ rspec-core (3.13.0)
61
+ rspec-support (~> 3.13.0)
62
+ rspec-expectations (3.13.0)
34
63
  diff-lcs (>= 1.2.0, < 2.0)
35
- rspec-support (~> 3.11.0)
36
- rspec-mocks (3.11.0)
64
+ rspec-support (~> 3.13.0)
65
+ rspec-mocks (3.13.0)
37
66
  diff-lcs (>= 1.2.0, < 2.0)
38
- rspec-support (~> 3.11.0)
39
- rspec-support (3.11.0)
40
- rubocop (1.25.1)
67
+ rspec-support (~> 3.13.0)
68
+ rspec-support (3.13.1)
69
+ rubocop (1.62.0)
70
+ json (~> 2.3)
71
+ language_server-protocol (>= 3.17.0)
41
72
  parallel (~> 1.10)
42
- parser (>= 3.1.0.0)
73
+ parser (>= 3.3.0.2)
43
74
  rainbow (>= 2.2.2, < 4.0)
44
75
  regexp_parser (>= 1.8, < 3.0)
45
- rexml
46
- rubocop-ast (>= 1.15.1, < 2.0)
76
+ rexml (>= 3.2.5, < 4.0)
77
+ rubocop-ast (>= 1.31.1, < 2.0)
47
78
  ruby-progressbar (~> 1.7)
48
- unicode-display_width (>= 1.4.0, < 3.0)
49
- rubocop-ast (1.16.0)
50
- parser (>= 3.1.1.0)
51
- rubocop-performance (1.13.2)
52
- rubocop (>= 1.7.0, < 2.0)
53
- rubocop-ast (>= 0.4.0)
79
+ unicode-display_width (>= 2.4.0, < 3.0)
80
+ rubocop-ast (1.31.2)
81
+ parser (>= 3.3.0.4)
82
+ rubocop-capybara (2.20.0)
83
+ rubocop (~> 1.41)
84
+ rubocop-factory_bot (2.25.1)
85
+ rubocop (~> 1.41)
86
+ rubocop-performance (1.20.2)
87
+ rubocop (>= 1.48.1, < 2.0)
88
+ rubocop-ast (>= 1.30.0, < 2.0)
54
89
  rubocop-rake (0.6.0)
55
90
  rubocop (~> 1.0)
56
- rubocop-rspec (2.9.0)
57
- rubocop (~> 1.19)
58
- ruby-progressbar (1.11.0)
59
- simplecov (0.21.2)
91
+ rubocop-rspec (2.27.1)
92
+ rubocop (~> 1.40)
93
+ rubocop-capybara (~> 2.17)
94
+ rubocop-factory_bot (~> 2.22)
95
+ ruby-openai (6.2.0)
96
+ event_stream_parser (>= 0.3.0, < 1.0.0)
97
+ faraday (>= 1)
98
+ faraday-multipart (>= 1)
99
+ ruby-progressbar (1.13.0)
100
+ simplecov (0.22.0)
60
101
  docile (~> 1.1)
61
102
  simplecov-html (~> 0.11)
62
103
  simplecov_json_formatter (~> 0.1)
@@ -64,7 +105,8 @@ GEM
64
105
  simplecov-lcov (0.8.0)
65
106
  simplecov_json_formatter (0.1.4)
66
107
  thor (1.2.2)
67
- unicode-display_width (2.1.0)
108
+ unicode-display_width (2.5.0)
109
+ uri (0.13.0)
68
110
 
69
111
  PLATFORMS
70
112
  ruby
@@ -82,6 +124,7 @@ DEPENDENCIES
82
124
  rubocop-rspec
83
125
  simplecov
84
126
  simplecov-lcov
127
+ uri (~> 0.13)
85
128
 
86
129
  BUNDLED WITH
87
130
  2.3.16
data/README.md CHANGED
@@ -28,6 +28,92 @@ Or install it yourself as:
28
28
  mj help
29
29
  ```
30
30
 
31
+ ### ChatGPT
32
+
33
+ ```
34
+ bundle exec mj chatgpt ask "Who won the World Cup in 1994?" --request-file samples/chatgpt/football-team.yml | jq
35
+ ```
36
+
37
+ Where the config file looks like:
38
+
39
+ ```yaml
40
+ request:
41
+ parameters:
42
+ model: gpt-3.5-turbo-16k
43
+ temperature: 0.1
44
+ messages:
45
+ - role: system
46
+ content: You re an expert in futebool history.
47
+ ```
48
+
49
+ Response:
50
+
51
+ ```json
52
+ {
53
+ "id": "chatcmpl-90a0HhlOIqYkMPRbuICPy5m798yjQ",
54
+ "object": "chat.completion",
55
+ "created": 1709925425,
56
+ "model": "gpt-3.5-turbo-16k-0613",
57
+ "choices": [
58
+ {
59
+ "index": 0,
60
+ "message": {
61
+ "role": "assistant",
62
+ "content": "The World Cup in 1994 was won by the Brazilian national team. They defeated Italy in the final match, which was held at the Rose Bowl stadium in Pasadena, California, United States. The match ended in a 0-0 draw after extra time, and Brazil won the penalty shootout 3-2 to claim their fourth World Cup title."
63
+ },
64
+ "logprobs": null,
65
+ "finish_reason": "stop"
66
+ }
67
+ ],
68
+ "usage": {
69
+ "prompt_tokens": 31,
70
+ "completion_tokens": 71,
71
+ "total_tokens": 102
72
+ },
73
+ "system_fingerprint": null
74
+ }
75
+ ```
76
+
77
+ You can also do `jq '.choices[0].message.content'`:
78
+
79
+ ```sh
80
+ mj chatgpt ask "Who won the World Cup in 1994?" \
81
+ --config-file samples/chatgpt/football-team.yml | jq '.choices[0].message.content'
82
+
83
+ # "The World Cup in 1994 was won by the Brazilian national team. They defeated Italy in the final match, which was held at the Rose Bowl stadium in Pasadena, California, United States. The match ended in a 0-0 draw after extra time, and Brazil won the penalty shootout 3-2 to claim their fourth World Cup title."
84
+ ```
85
+
86
+ ### GraphQl
87
+
88
+ ```
89
+ bundle exec mj graphql query_file AccountUsers.graphql | jq
90
+ ```
91
+
92
+ Your graqphql fiel is a regular file with variables at the top:
93
+
94
+ ```graphql
95
+ # gql-endpoint: http://api.myapi.me/graphql
96
+ # gql-header: Authorization: Bearer cb923f33617877578961a19cf4566ec2
97
+ # gql-header: Content-Type: application/json
98
+ # gql-variables: { "input": { "id": "some-id" } }
99
+
100
+ query QueryAccountUsers(
101
+ $input: AccountInput!
102
+ ) {
103
+ account(input: $input) {
104
+ users {
105
+ id
106
+ name
107
+ }
108
+ errors {
109
+ path
110
+ message
111
+ }
112
+ }
113
+ }
114
+ ```
115
+
116
+
31
117
  ### Alternative file
32
118
 
33
119
  Examples:
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mj
4
+ module ChatGpt
5
+ module Commands
6
+ class AskCommand
7
+ attr_reader :question
8
+ attr_reader :options
9
+
10
+ def initialize(question, options: {})
11
+ @question = question
12
+ @options = options
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openai"
4
+ require_relative "../request"
5
+
6
+ module Mj
7
+ module ChatGpt
8
+ module Commands
9
+ class AskCommandHandler
10
+ def initialize(client:)
11
+ @client = client
12
+ end
13
+
14
+ def handle(command)
15
+ request = Request.from_config_file(command.options.fetch("config_file"))
16
+ @client.chat(**request.asking(command.question).to_h)
17
+ rescue Faraday::Error => exception
18
+ {
19
+ error: exception.message,
20
+ body: exception.response&.dig(:body, "error") || exception.response
21
+ }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mj
4
+ module ChatGpt
5
+ class Request
6
+ def initialize(data = {})
7
+ @data = HashUtils.new.deep_symbolize_keys(data)
8
+ end
9
+
10
+ def asking(question)
11
+ data = @data.dup
12
+ data[:parameters] ||= {}
13
+ data[:parameters][:messages] ||= []
14
+ data[:parameters][:messages] << {
15
+ role: :user,
16
+ content: question
17
+ }
18
+ self.class.new(data)
19
+ end
20
+
21
+ def to_h
22
+ @data
23
+ end
24
+
25
+ def self.from_config_file(file)
26
+ data = YAML.load_file(file)
27
+ new(data.fetch("request"))
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "commands/ask_command_handler"
4
+ require_relative "commands/ask_command"
5
+
6
+ module Mj
7
+ module ChatGpt
8
+ class ThorCommand < Thor
9
+ desc "ask <question>", "Ask ChatGPT a question"
10
+ option :config_file, type: :string, desc: "Config file"
11
+ def ask(question)
12
+ client_config = {
13
+ access_token: ENV.fetch("OPENAI_ACCESS_TOKEN")
14
+ }
15
+ client = OpenAI::Client.new(**client_config.compact)
16
+ handler = Commands::AskCommandHandler.new(client: client)
17
+ data = handler.handle(Commands::AskCommand.new(question, options: options))
18
+ $stdout.puts JSON.generate(data)
19
+ end
20
+ end
21
+ end
22
+ end
data/lib/mj/cli.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  require "thor"
4
4
  require_relative "version"
5
5
  require_relative "alternative_file/thor_command"
6
+ require_relative "graphql/thor_command"
7
+ require_relative "chatgpt/thor_command"
6
8
 
7
9
  module Mj
8
10
  class Cli < Thor
@@ -17,5 +19,11 @@ module Mj
17
19
 
18
20
  desc "alternative_file", "Lists alternative files"
19
21
  subcommand "alternative_file", AlternativeFile::ThorCommand
22
+
23
+ desc "graphql", "CLI client for GraphQL"
24
+ subcommand "graphql", GraphQL::ThorCommand
25
+
26
+ desc "chatgpt", "CLI client for ChatGPT"
27
+ subcommand "chatgpt", ChatGpt::ThorCommand
20
28
  end
21
29
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "koine/rest_client"
4
+
5
+ module Mj
6
+ module GraphQL
7
+ class Client
8
+ def send(request)
9
+ base_url = request.endpoint.split("/graphql").first
10
+ base_request = Koine::RestClient::Request.new(base_url: base_url)
11
+ http_client = Koine::RestClient::Client.new(base_request: base_request)
12
+ http_client.post("/graphql", request.to_h, headers: request.headers)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mj
4
+ module GraphQL
5
+ module Commands
6
+ class QueryFileCommand
7
+ attr_reader :file
8
+ attr_reader :options
9
+
10
+ def initialize(file, options)
11
+ @file = file
12
+ @options = options
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../request_factory"
4
+ require_relative "../client"
5
+
6
+ module Mj
7
+ module GraphQL
8
+ module Commands
9
+ class QueryFileCommandHandler
10
+ def handle(command)
11
+ request = RequestFactory.new.from_file(command.file)
12
+ Client.new.send(request)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mj
4
+ module GraphQL
5
+ class Request
6
+ attr_reader :endpoint, :headers, :query, :variables
7
+
8
+ def initialize(endpoint: nil, query: nil, variables: {}, headers: {})
9
+ @endpoint = endpoint
10
+ @query = query
11
+ @variables = variables
12
+ @headers = headers
13
+ end
14
+
15
+ def with_header(name, value)
16
+ with(:headers, headers.merge(name => value))
17
+ end
18
+
19
+ def with_variables(variables)
20
+ with(:variables, variables)
21
+ end
22
+
23
+ def to_h
24
+ {
25
+ query: query,
26
+ variables: variables
27
+ }
28
+ end
29
+
30
+ private
31
+
32
+ def with(variable, value)
33
+ config = {
34
+ endpoint: endpoint,
35
+ query: query,
36
+ variables: variables,
37
+ headers: headers
38
+ }.merge(variable => value)
39
+
40
+ self.class.new(**config)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "request"
4
+
5
+ module Mj
6
+ module GraphQL
7
+ class RequestFactory
8
+ def from_file(file) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize, Metrics/MethodLength
9
+ contents = File.read(file)
10
+ comments = contents.split("\n").take_while { |line| line.match(/^#/) }.join("\n")
11
+ query = contents.split("\n").drop_while { |line| line.match(/^#/) }.join("\n")
12
+ endpoint = comments.match(/# gql-endpoint: (.+)/)&.captures&.first
13
+
14
+ request = Request.new(query: query, endpoint: endpoint)
15
+
16
+ headers = comments.split("\n")
17
+ .select { |line| line.match(/^# gql-header:/) }
18
+ .map { |line| line.split("gql-header:")[1..].join.strip }
19
+
20
+ headers.map do |value|
21
+ values = value.split(":").map(&:strip)
22
+ request = request.with_header(*values)
23
+ end
24
+
25
+ variables_string = comments.match(/# gql-variables:\s?(.+)/)&.captures&.first
26
+
27
+ if variables_string
28
+ variables = JSON.parse(variables_string)
29
+ request = request.with_variables(variables)
30
+ end
31
+
32
+ request
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "commands/query_file_command_handler"
4
+ require_relative "commands/query_file_command"
5
+ require "json"
6
+
7
+ module Mj
8
+ module GraphQL
9
+ class ThorCommand < Thor
10
+ desc "query_file <file>", "Execute a query based on a .graqphql file"
11
+ def query_file(file)
12
+ handler = Commands::QueryFileCommandHandler.new
13
+ data = handler.handle(Commands::QueryFileCommand.new(file, options))
14
+ $stdout.puts JSON.generate(data)
15
+ end
16
+ end
17
+ end
18
+ end
data/lib/mj/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mj
4
- VERSION = "0.6.2"
4
+ VERSION = "0.8.0"
5
5
  end
data/lib/mj.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "mj/version"
4
4
  require_relative "mj/cli"
5
+ require "mj/hash_utils"
5
6
 
6
7
  module Mj
7
8
  class Error < StandardError; end
data/mj.gemspec CHANGED
@@ -31,6 +31,9 @@ Gem::Specification.new do |spec|
31
31
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
32
  spec.require_paths = ["lib"]
33
33
 
34
+ spec.add_dependency "koine-rest_client"
35
+ spec.add_dependency "mj-hash_utils"
36
+ spec.add_dependency "ruby-openai", "~> 6.2.0"
34
37
  spec.add_dependency "thor", "~> 1.2.1"
35
38
 
36
39
  # For more information and examples about making a new gem, check out our
@@ -0,0 +1,10 @@
1
+ # samples/chatgpt/football-team.yml
2
+ # usage: bundle exec mj chatgpt ask "Who won the World Cup in 1994?" --config-file samples/chatgpt/football-team.yml | jq
3
+ request:
4
+ parameters:
5
+ model: gpt-3.5-turbo-16k
6
+ temperature: 0.1
7
+ max_tokens: 8192
8
+ messages:
9
+ - role: system
10
+ content: You re an expert in futebool history.
metadata CHANGED
@@ -1,15 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mj
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcelo Jacobus
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-05 00:00:00.000000000 Z
11
+ date: 2024-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: koine-rest_client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mj-hash_utils
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-openai
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 6.2.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 6.2.0
13
55
  - !ruby/object:Gem::Dependency
14
56
  name: thor
15
57
  requirement: !ruby/object:Gem::Requirement
@@ -58,9 +100,20 @@ files:
58
100
  - lib/mj/alternative_file/resolvers/ruby/vendored_gems_resolver.rb
59
101
  - lib/mj/alternative_file/resolvers/ruby/view_component_resolver.rb
60
102
  - lib/mj/alternative_file/thor_command.rb
103
+ - lib/mj/chatgpt/commands/ask_command.rb
104
+ - lib/mj/chatgpt/commands/ask_command_handler.rb
105
+ - lib/mj/chatgpt/request.rb
106
+ - lib/mj/chatgpt/thor_command.rb
61
107
  - lib/mj/cli.rb
108
+ - lib/mj/graphql/client.rb
109
+ - lib/mj/graphql/commands/query_file_command.rb
110
+ - lib/mj/graphql/commands/query_file_command_handler.rb
111
+ - lib/mj/graphql/request.rb
112
+ - lib/mj/graphql/request_factory.rb
113
+ - lib/mj/graphql/thor_command.rb
62
114
  - lib/mj/version.rb
63
115
  - mj.gemspec
116
+ - samples/chatgpt/football-team.yml
64
117
  - sig/mj.rbs
65
118
  homepage: https://github.com/mjacobus/mj
66
119
  licenses: