klue-langcraft 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +30 -3
  3. data/CHANGELOG.md +21 -0
  4. data/bin/dsl_watcher.rb +10 -0
  5. data/bin/langcraft.rb +177 -0
  6. data/docs/dsl-class-diagram.md +97 -0
  7. data/docs/dsl-examples.md +9 -0
  8. data/docs/dsl-upgrade-plan.md +266 -0
  9. data/lib/base_process.rb +41 -0
  10. data/lib/dsl_folder_watcher.rb +50 -0
  11. data/lib/dsl_interpreter.rb +112 -0
  12. data/lib/dsl_process_data.rb +31 -0
  13. data/lib/klue/langcraft/dsl/interpreter.rb +114 -0
  14. data/lib/klue/langcraft/dsl/klue_runner.rb +68 -0
  15. data/lib/klue/langcraft/dsl/process_data_pipeline.rb +65 -0
  16. data/lib/klue/langcraft/dsl/process_matcher.rb +59 -0
  17. data/lib/klue/langcraft/dsl/processor_config.rb +35 -0
  18. data/lib/klue/langcraft/dsl/processors/file_collector_processor.rb +30 -0
  19. data/lib/klue/langcraft/dsl/processors/full_name_processor.rb +34 -0
  20. data/lib/klue/langcraft/dsl/processors/processor.rb +43 -0
  21. data/lib/klue/langcraft/dsl/watcher.rb +88 -0
  22. data/lib/klue/langcraft/dsl/webhook.rb +57 -0
  23. data/lib/klue/langcraft/version.rb +1 -1
  24. data/lib/klue/langcraft.rb +29 -2
  25. data/lib/process_file_collector.rb +92 -0
  26. data/package-lock.json +2 -2
  27. data/package.json +1 -1
  28. metadata +39 -7
  29. data/docs/dsl-samples/index.md +0 -4
  30. /data/lib/klue/langcraft/{-brief.md → tokenizer-old-needs-revisit/-brief.md} +0 -0
  31. /data/lib/klue/langcraft/{parser.rb → tokenizer-old-needs-revisit/parser.rb} +0 -0
  32. /data/lib/klue/langcraft/{sample_usage.rb → tokenizer-old-needs-revisit/sample_usage.rb} +0 -0
  33. /data/lib/klue/langcraft/{tokenizer.rb → tokenizer-old-needs-revisit/tokenizer.rb} +0 -0
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'listen'
4
+
5
+ module Klue
6
+ module Langcraft
7
+ module DSL
8
+ # Watcher class for monitoring file changes in specified directories.
9
+ # This class sets up a file system listener to watch for changes to files
10
+ # with specified extensions, and processes those files using a KlueRunner.
11
+ class Watcher
12
+ def initialize(directories, **options)
13
+ @directories = directories.map { |dir| File.expand_path(dir) }
14
+ @options = options
15
+ @klue_runner = Klue::Langcraft::DSL::KlueRunner.new
16
+ @extensions = options[:extensions] || ['.klue']
17
+ end
18
+
19
+ def start
20
+ listener = create_listener
21
+ log_watcher_info
22
+ listener.start
23
+ sleep
24
+ end
25
+
26
+ private
27
+
28
+ def create_listener
29
+ extension_regex = create_extension_regex
30
+ Listen.to(*@directories, only: extension_regex) do |modified, added, _removed|
31
+ process_changed_files(modified + added)
32
+ end
33
+ end
34
+
35
+ def create_extension_regex
36
+ Regexp.union(@extensions.map { |ext| /#{Regexp.escape(ext)}$/ })
37
+ end
38
+
39
+ def process_changed_files(files)
40
+ files.each { |file| process_file(file) }
41
+ end
42
+
43
+ def process_file(file)
44
+ log_info('Processing file', file)
45
+ options = create_file_options(file)
46
+ run_klue_runner(options)
47
+ rescue StandardError => e
48
+ log_error('Error processing file', "#{file}: #{e.message}")
49
+ end
50
+
51
+ def create_file_options(file)
52
+ options = @options.dup
53
+ options[:input_file] = file
54
+ options[:basic_output_file] = file.sub(/#{File.extname(file)}$/, '.json') if @options[:create_basic_json]
55
+ options[:enhanced_output_file] = file.sub(/#{File.extname(file)}$/, '.enhanced.json') if @options[:create_enhanced_json]
56
+ options
57
+ end
58
+
59
+ def run_klue_runner(options)
60
+ @klue_runner.run(
61
+ input_file: options[:input_file],
62
+ basic_output_file: options[:basic_output_file],
63
+ enhanced_output_file: options[:enhanced_output_file],
64
+ webhook_url: options[:webhook_url],
65
+ log_level: options[:log_level]
66
+ )
67
+ end
68
+
69
+ def log_watcher_info
70
+ log_info('Watching directories', @directories.join(', '))
71
+ log_info('Watching file extensions', @extensions.join(', '))
72
+ log_info('Create basic JSON', @options[:create_basic_json])
73
+ log_info('Create enhanced JSON', @options[:create_enhanced_json])
74
+ log_info('Webhook URL', @options[:webhook_url])
75
+ log_info('Log level', @options[:log_level])
76
+ end
77
+
78
+ def log_info(label, value)
79
+ puts "#{label.ljust(30)}: #{value}" if %i[info detailed].include?(@options[:log_level])
80
+ end
81
+
82
+ def log_error(label, value)
83
+ puts "#{label.ljust(30)}: #{value}"
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'uri'
6
+
7
+ module Klue
8
+ module Langcraft
9
+ module DSL
10
+ # Webhook class for handling HTTP POST requests to specified URLs.
11
+ # This class is responsible for sending processed data to external services
12
+ # via webhooks, handling the delivery process, and logging the results.
13
+ class Webhook
14
+ def deliver(webhook_url, data)
15
+ klue_type = extract_klue_type(data)
16
+ uri = build_uri(webhook_url, klue_type)
17
+ response = send_request(uri, build_payload(klue_type, data))
18
+ log_response(response, uri)
19
+ response
20
+ end
21
+
22
+ private
23
+
24
+ def extract_klue_type(data)
25
+ data.keys.first.to_s
26
+ end
27
+
28
+ def build_uri(webhook_url, klue_type)
29
+ URI.parse("#{webhook_url}?klue-type=#{klue_type}")
30
+ end
31
+
32
+ def build_payload(klue_type, data)
33
+ { klue_type: klue_type, data: data }
34
+ end
35
+
36
+ def send_request(uri, payload)
37
+ http = Net::HTTP.new(uri.host, uri.port)
38
+ request = Net::HTTP::Post.new(uri.path, { 'Content-Type' => 'application/json' })
39
+ request.body = payload.to_json
40
+ http.request(request)
41
+ end
42
+
43
+ def log_response(response, uri)
44
+ puts "Response: #{response.code} - #{response.message}"
45
+ puts "Endpoint: #{uri}"
46
+ log_response_body(response)
47
+ end
48
+
49
+ def log_response_body(response)
50
+ body = JSON.parse(response.body)
51
+ puts "DSL Type: #{body['type']}"
52
+ # puts JSON.pretty_generate(body['data'])
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Klue
4
4
  module Langcraft
5
- VERSION = '0.1.1'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
@@ -1,6 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'uri'
6
+ require 'listen'
7
+ require 'pry'
8
+
9
+ require 'appydave/tools'
10
+
3
11
  require 'klue/langcraft/version'
12
+ require 'klue/langcraft/dsl/processor_config'
13
+
14
+ ProcessorConfigDefault = Klue::Langcraft::DSL::ProcessorConfig.new
15
+
16
+ require 'klue/langcraft/dsl/processors/processor'
17
+ require 'klue/langcraft/dsl/processors/file_collector_processor'
18
+ require 'klue/langcraft/dsl/processors/full_name_processor'
19
+ require 'klue/langcraft/dsl/interpreter'
20
+ require 'klue/langcraft/dsl/process_matcher'
21
+ require 'klue/langcraft/dsl/process_data_pipeline'
22
+ require 'klue/langcraft/dsl/webhook'
23
+ require 'klue/langcraft/dsl/watcher'
24
+ require 'klue/langcraft/dsl/klue_runner'
25
+
26
+ require 'base_process'
27
+ require 'process_file_collector'
28
+ require 'dsl_interpreter'
29
+ require 'dsl_folder_watcher'
30
+ require 'dsl_process_data'
4
31
 
5
32
  module Klue
6
33
  module Langcraft
@@ -12,8 +39,8 @@ module Klue
12
39
  end
13
40
 
14
41
  if ENV.fetch('KLUE_DEBUG', 'false').downcase == 'true'
15
- namespace = 'KlueLangcraft::Version'
42
+ namespace = 'Klue::Langcraft::Version'
16
43
  file_path = $LOADED_FEATURES.find { |f| f.include?('klue-langcraft/version') }
17
- version = KlueLangcraft::VERSION.ljust(9)
44
+ version = Klue::Langcraft::VERSION.ljust(9)
18
45
  puts "#{namespace.ljust(35)} : #{version.ljust(9)} : #{file_path}"
19
46
  end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ # file: lib/process_file_collector.rb
4
+
5
+ class ProcessFileCollector < BaseProcess
6
+ def initialize(key)
7
+ super
8
+ @found = nil
9
+ # @matcher = ->(key, value) { key.to_s == 'file_collector' && value.is_a?(Hash) }
10
+ @matcher = lambda do |key, value|
11
+ if key.to_s == 'file_collector'
12
+ if value.is_a?(Array)
13
+ value.any? { |v| v.is_a?(Hash) }
14
+ else
15
+ value.is_a?(Hash)
16
+ end
17
+ else
18
+ false
19
+ end
20
+ end
21
+ end
22
+
23
+ def match?(input)
24
+ @found = deep_match(input, @matcher)
25
+ !@found.empty?
26
+ end
27
+
28
+ def execute(_input)
29
+ # Iterate over each `file_collector` found and process individually
30
+ results = {}
31
+
32
+ @found.each do |data|
33
+ next unless data.is_a?(Hash)
34
+
35
+ # Extract the `as` key if present
36
+ as_key = data['as']
37
+
38
+ working_directory = File.expand_path(data['root'])
39
+
40
+ options = Appydave::Tools::GptContext::Options.new(
41
+ working_directory: working_directory,
42
+ include_patterns: extract_patterns(data.dig('files', 'include')),
43
+ exclude_patterns: extract_patterns(data.dig('files', 'exclude')),
44
+ format: 'json',
45
+ line_limit: data['line_length']
46
+ )
47
+
48
+ collector = Appydave::Tools::GptContext::FileCollector.new(options)
49
+ json = collector.build
50
+
51
+ # Structuring the result under `process-data` with `as` as key
52
+ result_data = {
53
+ type: 'file_collector',
54
+ data: {
55
+ working_directory: working_directory,
56
+ files: JSON.parse(json)
57
+ }
58
+ }
59
+
60
+ # If `as` key exists, use it to store under process-data with that identifier
61
+ if as_key
62
+ results[as_key] = result_data
63
+ else
64
+ # Generate a unique key if no `as` key is defined
65
+ unique_key = "file_collector_#{results.size + 1}"
66
+ results[unique_key] = result_data
67
+ end
68
+ end
69
+
70
+ results
71
+ rescue SyntaxError, NameError, NoMethodError => e
72
+ puts "Ruby evaluation error in ProcessFileCollector: #{e.message}"
73
+ puts "Error occurred at: #{e.backtrace.first}"
74
+ {}
75
+ rescue StandardError => e
76
+ puts "Unexpected error in ProcessFileCollector: #{e.message}"
77
+ puts e.backtrace.join("\n")
78
+ {}
79
+ end
80
+
81
+ private
82
+
83
+ def extract_patterns(files_data)
84
+ if files_data.is_a?(Hash)
85
+ [files_data['param1']]
86
+ elsif files_data.is_a?(Array)
87
+ files_data.map { |entry| entry['param1'] }
88
+ else
89
+ []
90
+ end
91
+ end
92
+ end
data/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "klue-langcraft",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "klue-langcraft",
9
- "version": "0.1.1",
9
+ "version": "0.3.0",
10
10
  "devDependencies": {
11
11
  "@klueless-js/semantic-release-rubygem": "github:klueless-js/semantic-release-rubygem",
12
12
  "@semantic-release/changelog": "^6.0.3",
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klue-langcraft",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Domain Specific Language Crafting",
5
5
  "scripts": {
6
6
  "release": "semantic-release"
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: klue-langcraft
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-22 00:00:00.000000000 Z
11
+ date: 2024-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: appydave-tools
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'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: k_log
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -47,27 +61,45 @@ files:
47
61
  - README.md
48
62
  - Rakefile
49
63
  - bin/console
64
+ - bin/dsl_watcher.rb
65
+ - bin/langcraft.rb
50
66
  - bin/setup
67
+ - docs/dsl-class-diagram.md
51
68
  - docs/dsl-examples.md
52
69
  - docs/dsl-rules.md
53
- - docs/dsl-samples/index.md
54
70
  - docs/dsl-samples/youtube-launch-optimizer-old.klue
55
71
  - docs/dsl-samples/youtube-launch-optimizer-strawberry.json
56
72
  - docs/dsl-samples/youtube-launch-optimizer-strawberry.klue
57
73
  - docs/dsl-samples/youtube-launch-optimizer.defn.klue
58
74
  - docs/dsl-samples/youtube-launch-optimizer.json
59
75
  - docs/dsl-samples/youtube-launch-optimizer.klue
76
+ - docs/dsl-upgrade-plan.md
60
77
  - docs/project-plan/project-plan.md
61
78
  - docs/project-plan/project.drawio
62
79
  - docs/project-plan/project_done.svg
63
80
  - docs/project-plan/project_in_progress.svg
64
81
  - docs/project-plan/project_todo.svg
82
+ - lib/base_process.rb
83
+ - lib/dsl_folder_watcher.rb
84
+ - lib/dsl_interpreter.rb
85
+ - lib/dsl_process_data.rb
65
86
  - lib/klue/langcraft.rb
66
- - lib/klue/langcraft/-brief.md
67
- - lib/klue/langcraft/parser.rb
68
- - lib/klue/langcraft/sample_usage.rb
69
- - lib/klue/langcraft/tokenizer.rb
87
+ - lib/klue/langcraft/dsl/interpreter.rb
88
+ - lib/klue/langcraft/dsl/klue_runner.rb
89
+ - lib/klue/langcraft/dsl/process_data_pipeline.rb
90
+ - lib/klue/langcraft/dsl/process_matcher.rb
91
+ - lib/klue/langcraft/dsl/processor_config.rb
92
+ - lib/klue/langcraft/dsl/processors/file_collector_processor.rb
93
+ - lib/klue/langcraft/dsl/processors/full_name_processor.rb
94
+ - lib/klue/langcraft/dsl/processors/processor.rb
95
+ - lib/klue/langcraft/dsl/watcher.rb
96
+ - lib/klue/langcraft/dsl/webhook.rb
97
+ - lib/klue/langcraft/tokenizer-old-needs-revisit/-brief.md
98
+ - lib/klue/langcraft/tokenizer-old-needs-revisit/parser.rb
99
+ - lib/klue/langcraft/tokenizer-old-needs-revisit/sample_usage.rb
100
+ - lib/klue/langcraft/tokenizer-old-needs-revisit/tokenizer.rb
70
101
  - lib/klue/langcraft/version.rb
102
+ - lib/process_file_collector.rb
71
103
  - package-lock.json
72
104
  - package.json
73
105
  - sig/klue/langcraft.rbs
@@ -1,4 +0,0 @@
1
- Printspeak DSL
2
- Project Plan
3
- Agent As Code
4
- Make Chapters out of my recordings using a folder and glob pattern geared to my naming convention