legionio 1.6.2 → 1.6.7
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 +4 -4
- data/CHANGELOG.md +41 -0
- data/lib/legion/api/codegen.rb +84 -0
- data/lib/legion/api.rb +2 -0
- data/lib/legion/cli/codegen_command.rb +104 -0
- data/lib/legion/cli/update_command.rb +35 -67
- data/lib/legion/cli.rb +4 -0
- data/lib/legion/extensions/actors/subscription.rb +3 -2
- data/lib/legion/service.rb +10 -0
- data/lib/legion/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e025887526f8b9e258eb168a14a83d5c34e60668eadbe9e1ccd5c995e27d725c
|
|
4
|
+
data.tar.gz: a85e52dc5ec39293461e7df402f2ea8f1a410d293c28141fc935cfb6023b71df
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6ecefca3ab028b370f8e590cf4fa81290e3a9e106f53a5655d11928f40ec99a0d48451ab94c9516086fd81bd5c42d4523eae4d975b9df667d8db7010656884c6
|
|
7
|
+
data.tar.gz: c5f4aa31b5431e6fb012991fe0048ac75c0d25d95e6402983590d7954491ad53e78b18d2911cb7969427cd60e63a47975d7ca89ff7642857cd857328dec559e3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Legion Changelog
|
|
2
2
|
|
|
3
|
+
## [1.6.7] - 2026-03-26
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- `setup_generated_functions` now runs only when `extensions: true` (inside the extensions gate) preventing unexpected boot side-effects in CLI flows that disable extensions
|
|
7
|
+
- Consumer tag entropy upgraded from `SecureRandom.hex(4)` (32-bit) to `SecureRandom.uuid` (122-bit) in both `prepare` and `subscribe` paths of subscription actor, eliminating the theoretical RabbitMQ `NOT_ALLOWED` tag collision
|
|
8
|
+
|
|
9
|
+
## [1.6.6] - 2026-03-26
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `legionio bootstrap SOURCE` command: combines `config import`, `config scaffold`, and `setup agentic` into one command
|
|
13
|
+
- Pre-flight checks for klist (Kerberos ticket), brew availability, and legionio binary
|
|
14
|
+
- `--skip-packs` flag to skip gem pack installation (config-only mode)
|
|
15
|
+
- `--start` flag to start redis + legionio via brew services after bootstrap
|
|
16
|
+
- `--force` flag to overwrite existing config files during bootstrap
|
|
17
|
+
- `--json` flag for machine-readable bootstrap output
|
|
18
|
+
- `shell_capture` helper extracted to make shell invocations stubbable in specs
|
|
19
|
+
- 62 specs covering preflight checks, pack extraction, config fetch/write delegation, pack install, summary output, all flags, and error handling
|
|
20
|
+
|
|
21
|
+
## [1.6.5] - 2026-03-26
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
- `Context.to_system_prompt` appends a live self-awareness section from `lex-agentic-self` Metacognition when the gem is loaded; logic extracted into `self_awareness_hint` helper to keep `to_system_prompt` within Metrics/CyclomaticComplexity limits; guarded with `defined?()` and `rescue StandardError`
|
|
25
|
+
|
|
26
|
+
## [1.6.4] - 2026-03-26
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- fix consumer tag collision on boot: subscription actors using `Thread.current.object_id` produced duplicate tags when `FixedThreadPool` reused threads, causing RabbitMQ `NOT_ALLOWED` connection kill and cascading errors; replaced with `SecureRandom.hex(4)`
|
|
30
|
+
|
|
31
|
+
## [1.6.3] - 2026-03-26
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- `legionio update` now uses `gem outdated` instead of custom HTTP client to check rubygems.org
|
|
35
|
+
- Remove `concurrent-ruby`, `net/http`, `json` dependencies from update command
|
|
36
|
+
- 4 persistent keep-alive connections replaced by single `gem outdated` call (~8s, 100% reliable)
|
|
37
|
+
|
|
3
38
|
## [1.6.2] - 2026-03-26
|
|
4
39
|
|
|
5
40
|
### Fixed
|
|
@@ -17,6 +52,12 @@
|
|
|
17
52
|
## [1.6.0] - 2026-03-26
|
|
18
53
|
|
|
19
54
|
### Added
|
|
55
|
+
- `legion codegen` CLI subcommand (status, list, show, approve, reject, retry, gaps, cycle)
|
|
56
|
+
- `/api/codegen/*` API routes for generated function management
|
|
57
|
+
- Boot loading for generated functions via GeneratedRegistry
|
|
58
|
+
- Function metadata DSL (function_outputs, function_category, function_tags, function_risk_tier, function_idempotent, function_requires, function_expose)
|
|
59
|
+
- ClassMethods for MCP tool exposure (expose_as_mcp_tool, mcp_tool_prefix)
|
|
60
|
+
- End-to-end integration test for self-generating functions
|
|
20
61
|
- `legion knowledge monitor add/list/remove/status` — multi-directory corpus monitor management
|
|
21
62
|
- `legion knowledge capture commit` — capture git commit as knowledge (hook-compatible)
|
|
22
63
|
- `legion knowledge capture session` — capture session summary as knowledge (hook-compatible)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
class API < Sinatra::Base
|
|
5
|
+
module Routes
|
|
6
|
+
module Codegen
|
|
7
|
+
def self.registered(app) # rubocop:disable Metrics/MethodLength
|
|
8
|
+
app.get '/api/codegen/status' do
|
|
9
|
+
halt 503, json_error('codegen_unavailable', 'codegen not available', status_code: 503) unless defined?(Legion::MCP::SelfGenerate)
|
|
10
|
+
|
|
11
|
+
json_response(Legion::MCP::SelfGenerate.status)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
app.get '/api/codegen/generated' do
|
|
15
|
+
unless defined?(Legion::Extensions::Codegen::Helpers::GeneratedRegistry)
|
|
16
|
+
halt 503, json_error('codegen_unavailable', 'codegen not available', status_code: 503)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
status_filter = params[:status]
|
|
20
|
+
records = Legion::Extensions::Codegen::Helpers::GeneratedRegistry.list(status: status_filter)
|
|
21
|
+
json_response(records)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
app.get '/api/codegen/generated/:id' do |id|
|
|
25
|
+
unless defined?(Legion::Extensions::Codegen::Helpers::GeneratedRegistry)
|
|
26
|
+
halt 503, json_error('codegen_unavailable', 'codegen not available', status_code: 503)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
record = Legion::Extensions::Codegen::Helpers::GeneratedRegistry.get(id: id)
|
|
30
|
+
halt 404, json_error('not_found', 'record not found', status_code: 404) unless record
|
|
31
|
+
|
|
32
|
+
json_response(record)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
app.post '/api/codegen/generated/:id/approve' do |id|
|
|
36
|
+
unless defined?(Legion::Extensions::Codegen::Runners::ReviewHandler)
|
|
37
|
+
halt 503, json_error('codegen_unavailable', 'review handler not available', status_code: 503)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
result = Legion::Extensions::Codegen::Runners::ReviewHandler.handle_verdict(
|
|
41
|
+
review: { generation_id: id, verdict: :approve, confidence: 1.0 }
|
|
42
|
+
)
|
|
43
|
+
json_response(result)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
app.post '/api/codegen/generated/:id/reject' do |id|
|
|
47
|
+
unless defined?(Legion::Extensions::Codegen::Helpers::GeneratedRegistry)
|
|
48
|
+
halt 503, json_error('codegen_unavailable', 'codegen not available', status_code: 503)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
Legion::Extensions::Codegen::Helpers::GeneratedRegistry.update_status(id: id, status: 'rejected')
|
|
52
|
+
json_response({ id: id, status: 'rejected' })
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
app.post '/api/codegen/generated/:id/retry' do |id|
|
|
56
|
+
unless defined?(Legion::Extensions::Codegen::Helpers::GeneratedRegistry)
|
|
57
|
+
halt 503, json_error('codegen_unavailable', 'codegen not available', status_code: 503)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
Legion::Extensions::Codegen::Helpers::GeneratedRegistry.update_status(id: id, status: 'pending')
|
|
61
|
+
json_response({ id: id, status: 'pending' })
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
app.get '/api/codegen/gaps' do
|
|
65
|
+
data = if defined?(Legion::MCP::GapDetector)
|
|
66
|
+
Legion::MCP::GapDetector.detect_gaps
|
|
67
|
+
else
|
|
68
|
+
[]
|
|
69
|
+
end
|
|
70
|
+
json_response(data)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
app.post '/api/codegen/cycle' do
|
|
74
|
+
return json_response({ triggered: false, reason: 'self_generate not available' }) unless defined?(Legion::MCP::SelfGenerate)
|
|
75
|
+
|
|
76
|
+
Legion::MCP::SelfGenerate.instance_variable_set(:@last_cycle_at, nil)
|
|
77
|
+
result = Legion::MCP::SelfGenerate.run_cycle
|
|
78
|
+
json_response(result)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
data/lib/legion/api.rb
CHANGED
|
@@ -46,6 +46,7 @@ require_relative 'api/apollo'
|
|
|
46
46
|
require_relative 'api/costs'
|
|
47
47
|
require_relative 'api/traces'
|
|
48
48
|
require_relative 'api/stats'
|
|
49
|
+
require_relative 'api/codegen'
|
|
49
50
|
require_relative 'api/graphql' if defined?(GraphQL)
|
|
50
51
|
|
|
51
52
|
module Legion
|
|
@@ -137,6 +138,7 @@ module Legion
|
|
|
137
138
|
register Routes::Costs
|
|
138
139
|
register Routes::Traces
|
|
139
140
|
register Routes::Stats
|
|
141
|
+
register Routes::Codegen
|
|
140
142
|
register Routes::GraphQL if defined?(Routes::GraphQL)
|
|
141
143
|
|
|
142
144
|
use Legion::API::Middleware::RequestLogger
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module CLI
|
|
5
|
+
class CodegenCommand < Thor
|
|
6
|
+
namespace :codegen
|
|
7
|
+
|
|
8
|
+
desc 'status', 'Show codegen cycle stats, pending gaps, registry counts'
|
|
9
|
+
def status
|
|
10
|
+
if defined?(Legion::MCP::SelfGenerate)
|
|
11
|
+
data = Legion::MCP::SelfGenerate.status
|
|
12
|
+
say Legion::JSON.dump({ data: data })
|
|
13
|
+
else
|
|
14
|
+
say Legion::JSON.dump({ error: 'codegen not available' })
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc 'list', 'List generated functions'
|
|
19
|
+
method_option :status, type: :string, desc: 'Filter by status'
|
|
20
|
+
def list
|
|
21
|
+
unless defined?(Legion::Extensions::Codegen::Helpers::GeneratedRegistry)
|
|
22
|
+
say Legion::JSON.dump({ error: 'codegen registry not available' })
|
|
23
|
+
return
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
records = Legion::Extensions::Codegen::Helpers::GeneratedRegistry.list(status: options[:status])
|
|
27
|
+
say Legion::JSON.dump({ data: records })
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
desc 'show ID', 'Show details of a generated function'
|
|
31
|
+
def show(id)
|
|
32
|
+
unless defined?(Legion::Extensions::Codegen::Helpers::GeneratedRegistry)
|
|
33
|
+
say Legion::JSON.dump({ error: 'codegen registry not available' })
|
|
34
|
+
return
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
record = Legion::Extensions::Codegen::Helpers::GeneratedRegistry.get(id: id)
|
|
38
|
+
if record
|
|
39
|
+
say Legion::JSON.dump({ data: record })
|
|
40
|
+
else
|
|
41
|
+
say Legion::JSON.dump({ error: 'not found' })
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
desc 'approve ID', 'Manually approve a parked generated function'
|
|
46
|
+
def approve(id)
|
|
47
|
+
unless defined?(Legion::Extensions::Codegen::Runners::ReviewHandler)
|
|
48
|
+
say Legion::JSON.dump({ error: 'review handler not available' })
|
|
49
|
+
return
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
result = Legion::Extensions::Codegen::Runners::ReviewHandler.handle_verdict(
|
|
53
|
+
review: { generation_id: id, verdict: :approve, confidence: 1.0 }
|
|
54
|
+
)
|
|
55
|
+
say Legion::JSON.dump({ data: result })
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
desc 'reject ID', 'Manually reject a generated function'
|
|
59
|
+
def reject(id)
|
|
60
|
+
unless defined?(Legion::Extensions::Codegen::Helpers::GeneratedRegistry)
|
|
61
|
+
say Legion::JSON.dump({ error: 'codegen registry not available' })
|
|
62
|
+
return
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
Legion::Extensions::Codegen::Helpers::GeneratedRegistry.update_status(id: id, status: 'rejected')
|
|
66
|
+
say Legion::JSON.dump({ data: { id: id, status: 'rejected' } })
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
desc 'retry ID', 'Re-queue a generated function for regeneration'
|
|
70
|
+
def retry_generation(id)
|
|
71
|
+
unless defined?(Legion::Extensions::Codegen::Helpers::GeneratedRegistry)
|
|
72
|
+
say Legion::JSON.dump({ error: 'codegen registry not available' })
|
|
73
|
+
return
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
Legion::Extensions::Codegen::Helpers::GeneratedRegistry.update_status(id: id, status: 'pending')
|
|
77
|
+
say Legion::JSON.dump({ data: { id: id, status: 'pending' } })
|
|
78
|
+
end
|
|
79
|
+
map 'retry' => :retry_generation
|
|
80
|
+
|
|
81
|
+
desc 'gaps', 'List detected capability gaps with priorities'
|
|
82
|
+
def gaps
|
|
83
|
+
if defined?(Legion::MCP::GapDetector)
|
|
84
|
+
detected = Legion::MCP::GapDetector.detect_gaps
|
|
85
|
+
say Legion::JSON.dump({ data: detected })
|
|
86
|
+
else
|
|
87
|
+
say Legion::JSON.dump({ error: 'gap detector not available' })
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
desc 'cycle', 'Manually trigger a generation cycle (bypass cooldown)'
|
|
92
|
+
def cycle
|
|
93
|
+
unless defined?(Legion::MCP::SelfGenerate)
|
|
94
|
+
say Legion::JSON.dump({ error: 'self_generate not available' })
|
|
95
|
+
return
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
Legion::MCP::SelfGenerate.instance_variable_set(:@last_cycle_at, nil)
|
|
99
|
+
result = Legion::MCP::SelfGenerate.run_cycle
|
|
100
|
+
say Legion::JSON.dump({ data: result })
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -3,9 +3,6 @@
|
|
|
3
3
|
require 'English'
|
|
4
4
|
require 'thor'
|
|
5
5
|
require 'rbconfig'
|
|
6
|
-
require 'concurrent'
|
|
7
|
-
require 'net/http'
|
|
8
|
-
require 'json'
|
|
9
6
|
require 'rubygems/uninstaller'
|
|
10
7
|
|
|
11
8
|
module Legion
|
|
@@ -81,83 +78,60 @@ module Legion
|
|
|
81
78
|
|
|
82
79
|
def update_gems(gem_names, gem_bin, dry_run: false)
|
|
83
80
|
local_versions = snapshot_versions(gem_names)
|
|
84
|
-
|
|
81
|
+
outdated_map = fetch_outdated(gem_bin, gem_names)
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
results = gem_names.map do |name|
|
|
84
|
+
info = outdated_map[name]
|
|
85
|
+
if info
|
|
86
|
+
{ name: name, from: local_versions[name], to: info[:remote], status: dry_run ? 'available' : 'pending' }
|
|
87
|
+
else
|
|
88
|
+
{ name: name, from: local_versions[name], status: 'current' }
|
|
89
|
+
end
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
return
|
|
92
|
+
return results if dry_run
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
pending = results.select { |r| r[:status] == 'pending' }
|
|
95
|
+
return results.each { |r| r[:status] = 'current' if r[:status] == 'pending' } if pending.empty?
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
install_outdated(gem_bin, pending, results)
|
|
97
98
|
end
|
|
98
99
|
|
|
99
|
-
def
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
status = if outdated.include?(name) then 'available'
|
|
103
|
-
elsif remote then 'current'
|
|
104
|
-
else 'check_failed'
|
|
105
|
-
end
|
|
106
|
-
{ name: name, from: local_versions[name], to: remote, status: status }
|
|
107
|
-
end
|
|
108
|
-
end
|
|
100
|
+
def fetch_outdated(gem_bin, gem_names)
|
|
101
|
+
output = `#{gem_bin} outdated 2>&1`
|
|
102
|
+
return {} unless $CHILD_STATUS.success?
|
|
109
103
|
|
|
110
|
-
|
|
111
|
-
gem_names.map do |name|
|
|
112
|
-
{ name: name, status: remote_versions[name] ? 'current' : 'check_failed', remote: remote_versions[name] }
|
|
113
|
-
end
|
|
104
|
+
parse_outdated(output, gem_names)
|
|
114
105
|
end
|
|
115
106
|
|
|
116
|
-
def
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
{ name: name, status: success ? 'installed' : 'failed', remote: remote_versions[name], output: output.strip }
|
|
122
|
-
else
|
|
123
|
-
{ name: name, status: remote_versions[name] ? 'current' : 'check_failed', remote: remote_versions[name] }
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
end
|
|
107
|
+
def parse_outdated(output, gem_names)
|
|
108
|
+
allowed = gem_names.to_set
|
|
109
|
+
output.each_line.with_object({}) do |line, map|
|
|
110
|
+
match = line.match(/^(\S+) \((\S+) < (\S+)\)/)
|
|
111
|
+
next unless match && allowed.include?(match[1])
|
|
127
112
|
|
|
128
|
-
|
|
129
|
-
results = Concurrent::Hash.new
|
|
130
|
-
thread_count = [gem_names.size, 4].min
|
|
131
|
-
slices = gem_names.each_slice((gem_names.size / thread_count.to_f).ceil).to_a
|
|
132
|
-
threads = slices.map do |batch|
|
|
133
|
-
Thread.new(batch) do |names|
|
|
134
|
-
fetch_batch(names, results)
|
|
135
|
-
end
|
|
113
|
+
map[match[1]] = { local: match[2], remote: match[3] }
|
|
136
114
|
end
|
|
137
|
-
threads.each { |t| t.join(60) }
|
|
138
|
-
results
|
|
139
115
|
end
|
|
140
116
|
|
|
141
|
-
def
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
117
|
+
def install_outdated(gem_bin, pending, results)
|
|
118
|
+
names = pending.map { |r| r[:name] }
|
|
119
|
+
`#{gem_bin} install #{names.join(' ')} --no-document 2>&1`
|
|
120
|
+
success = $CHILD_STATUS.success?
|
|
121
|
+
pending_set = names.to_set
|
|
122
|
+
results.each do |r|
|
|
123
|
+
r[:status] = if pending_set.include?(r[:name])
|
|
124
|
+
success ? 'installed' : 'failed'
|
|
125
|
+
else
|
|
126
|
+
'current'
|
|
127
|
+
end
|
|
152
128
|
end
|
|
153
|
-
|
|
154
|
-
Legion::Logging.debug("UpdateCommand#fetch_batch connection: #{e.message}") if defined?(Legion::Logging)
|
|
129
|
+
results
|
|
155
130
|
end
|
|
156
131
|
|
|
157
132
|
def display_results(out, results, before, after)
|
|
158
133
|
updated = []
|
|
159
134
|
failed = []
|
|
160
|
-
check_failures = 0
|
|
161
135
|
|
|
162
136
|
results.each do |r|
|
|
163
137
|
name = r[:name]
|
|
@@ -166,11 +140,7 @@ module Legion
|
|
|
166
140
|
puts " #{name}: #{r[:from]} -> #{r[:to]}"
|
|
167
141
|
updated << name
|
|
168
142
|
when 'current'
|
|
169
|
-
|
|
170
|
-
puts " #{name}: #{local || '?'} (already latest)"
|
|
171
|
-
when 'check_failed'
|
|
172
|
-
puts " #{name}: #{before[name]} (remote check failed)"
|
|
173
|
-
check_failures += 1
|
|
143
|
+
puts " #{name}: #{r[:from] || before[name] || '?'} (already latest)"
|
|
174
144
|
when 'installed'
|
|
175
145
|
old_v = before[name]
|
|
176
146
|
new_v = after[name]
|
|
@@ -190,8 +160,6 @@ module Legion
|
|
|
190
160
|
out.spacer
|
|
191
161
|
if updated.any?
|
|
192
162
|
out.success("Updated #{updated.size} gem(s)")
|
|
193
|
-
elsif check_failures.positive?
|
|
194
|
-
puts "#{check_failures} gem(s) could not be checked - retry or use --dry-run for details"
|
|
195
163
|
else
|
|
196
164
|
puts 'All gems are up to date'
|
|
197
165
|
end
|
data/lib/legion/cli.rb
CHANGED
|
@@ -64,6 +64,7 @@ module Legion
|
|
|
64
64
|
autoload :TraceCommand, 'legion/cli/trace_command'
|
|
65
65
|
autoload :Features, 'legion/cli/features_command'
|
|
66
66
|
autoload :Debug, 'legion/cli/debug_command'
|
|
67
|
+
autoload :CodegenCommand, 'legion/cli/codegen_command'
|
|
67
68
|
|
|
68
69
|
module Groups
|
|
69
70
|
autoload :Ai, 'legion/cli/groups/ai_group'
|
|
@@ -242,6 +243,9 @@ module Legion
|
|
|
242
243
|
subcommand 'init', Legion::CLI::Init
|
|
243
244
|
|
|
244
245
|
# --- Interactive & shortcuts ---
|
|
246
|
+
desc 'codegen SUBCOMMAND', 'Manage self-generating functions'
|
|
247
|
+
subcommand 'codegen', CodegenCommand
|
|
248
|
+
|
|
245
249
|
desc 'tty', 'Rich terminal UI (onboarding, AI chat, dashboard)'
|
|
246
250
|
subcommand 'tty', Legion::CLI::Tty
|
|
247
251
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'base'
|
|
4
4
|
require 'date'
|
|
5
|
+
require 'securerandom'
|
|
5
6
|
|
|
6
7
|
module Legion
|
|
7
8
|
module Extensions
|
|
@@ -50,7 +51,7 @@ module Legion
|
|
|
50
51
|
def prepare # rubocop:disable Metrics/AbcSize
|
|
51
52
|
@queue = queue.new
|
|
52
53
|
@queue.channel.prefetch(prefetch) if defined? prefetch
|
|
53
|
-
consumer_tag = "#{Legion::Settings[:client][:name]}_#{lex_name}_#{runner_name}_#{
|
|
54
|
+
consumer_tag = "#{Legion::Settings[:client][:name]}_#{lex_name}_#{runner_name}_#{SecureRandom.uuid}"
|
|
54
55
|
@consumer = Bunny::Consumer.new(@queue.channel, @queue, consumer_tag, false, false)
|
|
55
56
|
@consumer.on_delivery do |delivery_info, metadata, payload|
|
|
56
57
|
message = process_message(payload, metadata, delivery_info)
|
|
@@ -150,7 +151,7 @@ module Legion
|
|
|
150
151
|
def subscribe # rubocop:disable Metrics/AbcSize
|
|
151
152
|
log.info "[Subscription] subscribing: #{lex_name}/#{runner_name}"
|
|
152
153
|
sleep(delay_start) if delay_start.positive?
|
|
153
|
-
consumer_tag = "#{Legion::Settings[:client][:name]}_#{lex_name}_#{runner_name}_#{
|
|
154
|
+
consumer_tag = "#{Legion::Settings[:client][:name]}_#{lex_name}_#{runner_name}_#{SecureRandom.uuid}"
|
|
154
155
|
on_cancellation = block { cancel }
|
|
155
156
|
|
|
156
157
|
@consumer = @queue.subscribe(manual_ack: manual_ack, block: false, consumer_tag: consumer_tag, on_cancellation: on_cancellation) do |*rmq_message|
|
data/lib/legion/service.rb
CHANGED
|
@@ -126,6 +126,7 @@ module Legion
|
|
|
126
126
|
if extensions
|
|
127
127
|
load_extensions
|
|
128
128
|
Legion::Readiness.mark_ready(:extensions)
|
|
129
|
+
setup_generated_functions
|
|
129
130
|
end
|
|
130
131
|
|
|
131
132
|
Legion::Gaia.registry&.rediscover if gaia && defined?(Legion::Gaia) && Legion::Gaia.started?
|
|
@@ -612,6 +613,15 @@ module Legion
|
|
|
612
613
|
Legion::Extensions.hook_extensions
|
|
613
614
|
end
|
|
614
615
|
|
|
616
|
+
def setup_generated_functions
|
|
617
|
+
return unless defined?(Legion::Extensions::Codegen::Helpers::GeneratedRegistry)
|
|
618
|
+
|
|
619
|
+
loaded = Legion::Extensions::Codegen::Helpers::GeneratedRegistry.load_on_boot
|
|
620
|
+
Legion::Logging.info("Loaded #{loaded} generated functions") if defined?(Legion::Logging) && loaded.to_i.positive?
|
|
621
|
+
rescue StandardError => e
|
|
622
|
+
Legion::Logging.warn("setup_generated_functions failed: #{e.message}") if defined?(Legion::Logging)
|
|
623
|
+
end
|
|
624
|
+
|
|
615
625
|
def setup_mtls_rotation
|
|
616
626
|
enabled = Legion::Settings[:security]&.dig(:mtls, :enabled)
|
|
617
627
|
return unless enabled
|
data/lib/legion/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: legionio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.6.
|
|
4
|
+
version: 1.6.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -447,6 +447,7 @@ files:
|
|
|
447
447
|
- lib/legion/api/capacity.rb
|
|
448
448
|
- lib/legion/api/catalog.rb
|
|
449
449
|
- lib/legion/api/chains.rb
|
|
450
|
+
- lib/legion/api/codegen.rb
|
|
450
451
|
- lib/legion/api/coldstart.rb
|
|
451
452
|
- lib/legion/api/costs.rb
|
|
452
453
|
- lib/legion/api/events.rb
|
|
@@ -576,6 +577,7 @@ files:
|
|
|
576
577
|
- lib/legion/cli/chat_command.rb
|
|
577
578
|
- lib/legion/cli/check/privacy_check.rb
|
|
578
579
|
- lib/legion/cli/check_command.rb
|
|
580
|
+
- lib/legion/cli/codegen_command.rb
|
|
579
581
|
- lib/legion/cli/cohort.rb
|
|
580
582
|
- lib/legion/cli/coldstart_command.rb
|
|
581
583
|
- lib/legion/cli/commit_command.rb
|