lex-factory 0.1.0 → 0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df3fc328fe57d371e7b812ac1285a75dd022e38c7c33612e21292ddabd15de4c
4
- data.tar.gz: 7722b25f034cc3aaea6d8e6963f47907dec10bf27831d3afbf9bf633c12bc84f
3
+ metadata.gz: 3acf180b15bcba7e4c947f454d552620b04c2251eb62aed7a8214bfa88ecc2be
4
+ data.tar.gz: 8d04ca9595404aaefd7fc54f07cef8e8a70099b4a18f2553d05a0774a3922dec
5
5
  SHA512:
6
- metadata.gz: da95c3eedec07c08767cedf334bc7d96efbe4fe2aeeb3ce788c90121f8195cc697218b45f0624022bd7e6a60c868799f378ba6c79669cea31d647d870d74ec95
7
- data.tar.gz: 692244c9e64ca57b461433dffb757122fa68cc7eb670cc7ac2fbedfdc9651a7f31c8dd65ba9179696a60ffba70dd70e4985fed389663b899bede586638ca9dff
6
+ metadata.gz: 9f20b6cf1089657e6a3946bd4dbdde46239beb55c528b7e10ff4a40c91a4c17392bd9dcc0254050e2100ebc80564041c6aef33cafb9af17a873c790d48ca756f
7
+ data.tar.gz: 99362119a0d5bc9d649b358b145df44119dd57f5578a4f08fa1b1cc36dcebd5e821f32b38c45059f91c907399c51d12c5c32539fd4940ea64ba71aea220d343b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.2] - 2026-03-28
4
+
5
+ ### Changed
6
+ - Implement develop stage via real LLM code generation, delegating to `lex-codegen` `FromGap.generate`
7
+ - Graceful fallback to stub strategy when lex-codegen is not loaded
8
+ - Exclude `pipeline_runner.rb` from `Metrics/ClassLength` and `Metrics/AbcSize` in rubocop config
9
+
10
+ ## [0.1.1] - 2026-03-26
11
+
12
+ ### Changed
13
+ - fix remote_invocable? to use class method for local dispatch
14
+
3
15
  ## [0.1.0] - 2026-03-24
4
16
 
5
17
  ### Added
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
3
+ require 'legion/json'
4
4
  require 'fileutils'
5
5
 
6
6
  module Legion
7
7
  module Extensions
8
8
  module Factory
9
9
  class PipelineRunner
10
+ include Legion::JSON::Helper
11
+ include Legion::Logging::Helper
12
+
10
13
  attr_reader :spec_path, :output_dir
11
14
 
12
15
  def initialize(spec_path:, output_dir: nil, threshold: nil, max_retries: nil)
@@ -39,6 +42,7 @@ module Legion
39
42
  output_dir: @output_dir
40
43
  }
41
44
  rescue StandardError => e
45
+ log.error "PipelineRunner#run failed at stage #{@context[:current_stage]}: #{e.message}"
42
46
  save_state
43
47
  { success: false, error: e.message, last_stage: @context[:current_stage] }
44
48
  end
@@ -78,11 +82,14 @@ module Legion
78
82
 
79
83
  def stage_develop(ctx)
80
84
  tasks = ctx.dig(:define, :tasks) || []
81
- tasks.each { |t| t[:status] = :completed }
82
- ctx[:develop] = {
83
- tasks_completed: tasks.size,
84
- tasks_failed: 0
85
- }
85
+
86
+ if codegen_available?
87
+ develop_with_codegen(ctx, tasks)
88
+ else
89
+ tasks.each { |t| t[:status] = :completed }
90
+ ctx[:develop] = { tasks_completed: tasks.size, tasks_failed: 0, strategy: :stub }
91
+ end
92
+
86
93
  ctx
87
94
  end
88
95
 
@@ -106,6 +113,59 @@ module Legion
106
113
  ctx
107
114
  end
108
115
 
116
+ def codegen_available?
117
+ defined?(Legion::Extensions::Codegen::Runners::FromGap) &&
118
+ Legion::Extensions::Codegen::Runners::FromGap.respond_to?(:generate)
119
+ end
120
+
121
+ def develop_with_codegen(ctx, tasks)
122
+ counters = { completed: 0, failed: 0 }
123
+ artifacts = []
124
+
125
+ tasks.each { |task| run_codegen_task(task, counters, artifacts) }
126
+
127
+ ctx[:develop] = build_develop_context(ctx, counters, artifacts)
128
+ end
129
+
130
+ def run_codegen_task(task, counters, artifacts)
131
+ result = Legion::Extensions::Codegen::Runners::FromGap.generate(
132
+ gap: { id: task[:id], type: :runner_method, intent: task[:requirement] }
133
+ )
134
+ apply_task_result(task, result, counters, artifacts)
135
+ rescue StandardError => e
136
+ log.error "PipelineRunner#run_codegen_task failed for task #{task[:id]}: #{e.message}"
137
+ task[:status] = :failed
138
+ task[:reason] = e.message
139
+ counters[:failed] += 1
140
+ end
141
+
142
+ def apply_task_result(task, result, counters, artifacts)
143
+ if result[:success]
144
+ task[:status] = :completed
145
+ task[:generation_id] = result[:generation_id]
146
+ task[:file_path] = result[:file_path]
147
+ artifacts << result
148
+ counters[:completed] += 1
149
+ else
150
+ task[:status] = :failed
151
+ task[:reason] = result[:reason]
152
+ counters[:failed] += 1
153
+ end
154
+ end
155
+
156
+ def build_develop_context(ctx, counters, artifacts)
157
+ {
158
+ tasks_completed: counters[:completed],
159
+ tasks_failed: counters[:failed],
160
+ strategy: :codegen,
161
+ spec_title: ctx.dig(:discover, :title) || 'unknown',
162
+ spec_length: (ctx[:raw_spec] || '').length,
163
+ artifacts: artifacts.map do |a|
164
+ { generation_id: a[:generation_id], tier: a[:tier], file_path: a[:file_path] }
165
+ end
166
+ }
167
+ end
168
+
109
169
  def extract_requirements(parsed)
110
170
  return [] unless parsed[:success]
111
171
 
@@ -120,19 +180,21 @@ module Legion
120
180
 
121
181
  def save_state
122
182
  ::FileUtils.mkdir_p(@output_dir)
123
- File.write(state_file_path, ::JSON.generate(serialize_context(@context)))
124
- rescue StandardError
183
+ File.write(state_file_path, json_dump(serialize_context(@context)))
184
+ rescue StandardError => e
185
+ log.warn "PipelineRunner#save_state failed: #{e.message}"
125
186
  nil
126
187
  end
127
188
 
128
189
  def load_state
129
190
  return default_context unless File.exist?(state_file_path)
130
191
 
131
- data = ::JSON.parse(File.read(state_file_path), symbolize_names: true)
192
+ data = json_load(File.read(state_file_path))
132
193
  data[:completed_stages] = (data[:completed_stages] || []).map(&:to_sym)
133
194
  data[:current_stage] = data[:current_stage]&.to_sym
134
195
  data
135
- rescue StandardError
196
+ rescue StandardError => e
197
+ log.warn "PipelineRunner#load_state failed: #{e.message}"
136
198
  default_context
137
199
  end
138
200
 
@@ -161,7 +223,8 @@ module Legion
161
223
  return {} unless defined?(Legion::Settings) && !Legion::Settings[:factory].nil?
162
224
 
163
225
  Legion::Settings[:factory] || {}
164
- rescue StandardError
226
+ rescue StandardError => e
227
+ log.debug "PipelineRunner#factory_settings failed: #{e.message}"
165
228
  {}
166
229
  end
167
230
  end
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Factory
6
- VERSION = '0.1.0'
6
+ VERSION = '0.1.2'
7
7
  end
8
8
  end
9
9
  end
@@ -20,6 +20,10 @@ module Legion
20
20
  def llm_required?
21
21
  true
22
22
  end
23
+
24
+ def remote_invocable?
25
+ false
26
+ end
23
27
  end
24
28
  end
25
29
  end
metadata CHANGED
@@ -1,14 +1,42 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-factory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
8
8
  bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
- dependencies: []
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: legion-json
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.2'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '1.2'
26
+ - !ruby/object:Gem::Dependency
27
+ name: legion-logging
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0.3'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0.3'
12
40
  description: Double Diamond pipeline that takes a specification and produces working
13
41
  code with tests
14
42
  email: