legionio 1.6.26 → 1.6.29

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: 87e232e8560f2fc19eab52867dca532552949fa8ab6f2637f505454ce7c3f435
4
- data.tar.gz: d98b360b63301c86f808f2b0f2baac8c4671c871847233eb9a6d9f5ca5dd9b61
3
+ metadata.gz: f3a73a5c562d8c349f10592682acdfebc23bd0d5bc3cea80286be00d8b72aff4
4
+ data.tar.gz: a789defca2fbe696da75046a45f003eb49e6247fb102e5994d3a9bb57c8b9edf
5
5
  SHA512:
6
- metadata.gz: 77bc48601a5384ac7b2b9e9185eebb73a9882b492e15e811b1377b29d672758e648a49a5385e1287e2b49724e4e7e2393ee1452b79cd700aac5171a21cf624e3
7
- data.tar.gz: 7e31cd03e21c4263bb6b64dbfa0d7e7ef3aa51e0ecfa8801292084cc97ce6850c9795620dbb3fc3f235b9efd84c71a99b1ff41580f34524fcfdd8448b6f48225
6
+ metadata.gz: 734077acd813bbc111cb6613f8046873370d5db6f1c6208127eefefa318ea4afbe947205f721cbd2d2e08b47166f315735fbdb6fd64a69a376bff8cee9ec7986
7
+ data.tar.gz: ed8bbee89db76679597caade809ebc1a6ceb5ac2c7664456f01e693ac3cf899d28716dc493de2911bf723e02c15ec56d135326a8fbdaf4fb7870434b8bfef3a7
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.6.29] - 2026-03-28
6
+
7
+ ### Fixed
8
+ - Fallback route guards in `api.rb` now check `router.library_names.include?` instead of `defined?` — prevents 404s when gem modules are loaded but routes are not yet mounted (fixes #53)
9
+
10
+ ## [1.6.28] - 2026-03-28
11
+
12
+ ### Fixed
13
+ - `legion lex list` now displays extensions in clean aligned tables with Name, Version, Status, Runners, Actors columns
14
+ - Grouped view drops redundant category/tier columns from rows (already shown in group header); sorts alphabetically within each group
15
+ - Flat/category-filtered view uses Name, Version, Category, Status, Runners, Actors columns; sorts alphabetically
16
+ - Runners and actors are formatted as comma-joined names (up to 3) or a count summary instead of raw `Array#to_s` output
17
+ - JSON output for both flat and grouped list modes is now handled directly in the render methods
18
+
19
+ ## [1.6.27] - 2026-03-28
20
+
21
+ ### Fixed
22
+ - `Connection.ensure_crypt` now calls `resolve_secrets!` a second time after `Legion::Crypt.start` so that `lease://` URI refs are resolved once the LeaseManager is running (closes #50)
23
+
5
24
  ## [1.6.26] - 2026-03-28
6
25
 
7
26
  ### Added
data/CLAUDE.md CHANGED
@@ -99,7 +99,7 @@ Legion (lib/legion.rb)
99
99
  │ │ ├── Runners # Build runners from extension definitions (stores runner_module ref)
100
100
  │ │ ├── Helpers # Builder utilities
101
101
  │ │ ├── Hooks # Webhook hook system builder
102
- │ │ └── Routes # Auto-route builder: introspects runners, registers POST /api/lex/* routes
102
+ │ │ └── Routes # Auto-route builder: introspects runners, registers POST /api/extensions/* routes
103
103
  │ ├── Helpers/ # Helper mixins for extensions
104
104
  │ │ ├── Base # Base helper mixin
105
105
  │ │ ├── Core # Core helper mixin
@@ -130,7 +130,7 @@ Legion (lib/legion.rb)
130
130
  │ │ ├── Events # SSE stream (sinatra stream) + ring buffer polling fallback
131
131
  │ │ ├── Transport # Connection status, exchanges, queues, publish
132
132
  │ │ ├── Hooks # List + trigger registered extension hooks
133
- │ │ ├── Lex # Auto-routes: `POST /api/lex/*` wildcard + `GET /api/lex` listing
133
+ │ │ ├── LexDispatch # Dispatch: `POST /api/extensions/:lex/:type/:component/:method` + discovery GET
134
134
  │ │ ├── Workers # Digital worker lifecycle (`/api/workers/*`) + team routes (`/api/teams/*`)
135
135
  │ │ ├── Coldstart # `POST /api/coldstart/ingest` — trigger lex-coldstart ingest from API
136
136
  │ │ ├── Capacity # Aggregate, forecast, per-worker capacity endpoints
@@ -145,10 +145,8 @@ Legion (lib/legion.rb)
145
145
  │ │ ├── ApiVersion # `/api/v1/` rewrite, Deprecation/Sunset headers
146
146
  │ │ ├── BodyLimit # Request body size limit (1MB max, returns 413)
147
147
  │ │ └── RateLimit # Sliding-window rate limiting with per-IP/agent/tenant tiers
148
- ├── hook_registry # Class-level registry: register_hook, find_hook, registered_hooks
149
- # Populated by extensions via Legion::API.register_hook(...)
150
- │ └── route_registry # Class-level registry: register_route, find_route_by_path, registered_routes
151
- │ # Populated by Builders::Routes during autobuild
148
+ └── router # Class-level Router: extension_names, find_extension_route, registered_routes
149
+ # Populated by Builders::Routes during autobuild via LexDispatch
152
150
 
153
151
  ├── MCP (legion-mcp gem) # Extracted to standalone gem — see legion-mcp/CLAUDE.md
154
152
  │ └── (58 tools, 2 resources, TierRouter, PatternStore, ContextGuard, Observer, EmbeddingIndex)
@@ -609,8 +607,7 @@ rack-test, rake, rspec, rubocop, rubocop-rspec, simplecov
609
607
  | `lib/legion/api/settings.rb` | Settings: read/write with redaction + readonly guards |
610
608
  | `lib/legion/api/events.rb` | Events: SSE stream + polling fallback (ring buffer) |
611
609
  | `lib/legion/api/transport.rb` | Transport: status, exchanges, queues, publish |
612
- | `lib/legion/api/hooks.rb` | Hooks: list registered + trigger via Ingress; supports custom response headers |
613
- | `lib/legion/api/lex.rb` | Lex auto-routes: `POST /api/lex/*` wildcard dispatch + `GET /api/lex` listing |
610
+ | `lib/legion/api/lex_dispatch.rb` | LexDispatch: `POST /api/extensions/:lex/:type/:component/:method` dispatch + `GET` discovery; remote AMQP forwarding, hook-aware routing via `Routes::LexDispatch` |
614
611
  | `lib/legion/api/workers.rb` | Workers + Teams: digital worker lifecycle REST endpoints (`/api/workers/*`) and team cost endpoints (`/api/teams/*`) |
615
612
  | `lib/legion/api/coldstart.rb` | Coldstart: `POST /api/coldstart/ingest` — triggers lex-coldstart ingest runner (requires lex-coldstart + lex-memory) |
616
613
  | `lib/legion/api/gaia.rb` | Gaia: system status endpoints |
@@ -731,6 +728,7 @@ rack-test, rake, rspec, rubocop, rubocop-rspec, simplecov
731
728
  | `lib/legion/cli/doctor/` | Individual check modules: ruby_version, bundle, config, rabbitmq, database, cache, vault, extensions, pid, permissions, plus result.rb |
732
729
  | `lib/legion/cli/telemetry_command.rb` | `legion telemetry` subcommands (stats, ingest) — session log analytics |
733
730
  | `lib/legion/cli/auth_command.rb` | `legion auth` subcommands (teams) — delegated OAuth browser flow for external services |
731
+ | `lib/legion/cli/admin_command.rb` | `legion admin` subcommands (purge-topology) — ops tooling for v2.0 AMQP topology cleanup |
734
732
  | `completions/legion.bash` | Bash tab completion script |
735
733
  | `completions/_legion` | Zsh tab completion script |
736
734
  | `lib/legion/cli/theme.rb` | Purple palette, orbital ASCII banner, branded CLI output |
data/lib/legion/api.rb CHANGED
@@ -128,6 +128,13 @@ module Legion
128
128
  })
129
129
  end
130
130
 
131
+ # Tier-aware router (three-tier namespace)
132
+ class << self
133
+ def router
134
+ @router ||= Legion::API::Router.new
135
+ end
136
+ end
137
+
131
138
  # Mount route modules
132
139
  register Routes::LexDispatch
133
140
  register Routes::Tasks
@@ -139,11 +146,11 @@ module Legion
139
146
  register Routes::Chains
140
147
  register Routes::Settings
141
148
  register Routes::Events
142
- register Routes::Transport unless defined?(Legion::Transport::Routes)
149
+ register Routes::Transport unless router.library_names.include?('transport')
143
150
  register Routes::Workers
144
151
  register Routes::Coldstart
145
- register Routes::Gaia unless defined?(Legion::Gaia::Routes)
146
- register Routes::Rbac unless defined?(Legion::Rbac::Routes)
152
+ register Routes::Gaia unless router.library_names.include?('gaia')
153
+ register Routes::Rbac unless router.library_names.include?('rbac')
147
154
  register Routes::Auth
148
155
  register Routes::AuthWorker
149
156
  register Routes::AuthHuman
@@ -151,14 +158,14 @@ module Legion
151
158
  register Routes::Capacity
152
159
  register Routes::Audit
153
160
  register Routes::Metrics
154
- register Routes::Llm unless defined?(Legion::LLM::Routes)
161
+ register Routes::Llm unless router.library_names.include?('llm')
155
162
  register Routes::ExtensionCatalog
156
163
  register Routes::OrgChart
157
164
  register Routes::Governance
158
165
  register Routes::Acp
159
166
  register Routes::Prompts
160
167
  register Routes::Marketplace
161
- register Routes::Apollo unless defined?(Legion::Apollo::Routes)
168
+ register Routes::Apollo unless router.library_names.include?('apollo')
162
169
  register Routes::Costs
163
170
  register Routes::Traces
164
171
  register Routes::Stats
@@ -167,12 +174,5 @@ module Legion
167
174
 
168
175
  use Legion::API::Middleware::RequestLogger
169
176
  use Legion::Rbac::Middleware if defined?(Legion::Rbac::Middleware)
170
-
171
- # Tier-aware router (three-tier namespace)
172
- class << self
173
- def router
174
- @router ||= Legion::API::Router.new
175
- end
176
- end
177
177
  end
178
178
  end
@@ -69,6 +69,8 @@ module Legion
69
69
  ensure_settings
70
70
  require 'legion/crypt'
71
71
  Legion::Crypt.start
72
+ # Re-resolve now that LeaseManager is available for lease:// URIs
73
+ Legion::Settings.resolve_secrets! if Legion::Settings.respond_to?(:resolve_secrets!)
72
74
  @crypt_ready = true
73
75
  rescue LoadError
74
76
  raise CLI::Error, 'legion-crypt gem is not installed (gem install legion-crypt)'
@@ -299,22 +299,48 @@ module Legion
299
299
  end
300
300
  end
301
301
 
302
+ def format_runners(runners)
303
+ return '-' unless runners.is_a?(Array) && runners.any?
304
+
305
+ runners.length <= 3 ? runners.join(', ') : "#{runners.length} runners"
306
+ end
307
+
308
+ def format_actors(actors)
309
+ return '-' unless actors.is_a?(Array) && actors.any?
310
+
311
+ names = actors.map { |a| a.is_a?(Hash) ? a[:name] : a.to_s }
312
+ names.length <= 3 ? names.join(', ') : "#{names.length} actors"
313
+ end
314
+
302
315
  def render_flat_table(out, rows)
303
- table_rows = rows.map do |l|
304
- [l[:name], l[:version], l[:category].to_s, l[:tier].to_s, out.status(l[:status]), l[:runners].to_s, l[:actors].to_s]
316
+ if options[:json]
317
+ out.json(rows)
318
+ return
319
+ end
320
+
321
+ table_rows = rows.sort_by { |l| l[:name] }.map do |l|
322
+ [l[:name], l[:version], l[:category].to_s, out.status(l[:status]),
323
+ format_runners(l[:runners]), format_actors(l[:actors])]
305
324
  end
306
- out.table(%w[name version category tier status runners actors], table_rows)
325
+ out.table(%w[name version category status runners actors], table_rows)
307
326
  end
308
327
 
309
328
  def render_grouped_table(out, rows)
329
+ if options[:json]
330
+ out.json(rows)
331
+ return
332
+ end
333
+
310
334
  grouped = rows.group_by { |l| [l[:tier], l[:category]] }
311
335
  grouped.keys.sort_by { |tier, cat| [tier, cat.to_s] }.each do |key|
312
336
  tier, cat = key
313
- out.header("=== #{cat} (tier #{tier}) ===")
314
- group_rows = grouped[key].map do |l|
315
- [l[:name], l[:version], l[:category].to_s, l[:tier].to_s, out.status(l[:status]), l[:runners].to_s, l[:actors].to_s]
337
+ out.spacer
338
+ out.header("#{cat} (tier #{tier})")
339
+ group_rows = grouped[key].sort_by { |l| l[:name] }.map do |l|
340
+ [l[:name], l[:version], out.status(l[:status]),
341
+ format_runners(l[:runners]), format_actors(l[:actors])]
316
342
  end
317
- out.table(%w[name version category tier status runners actors], group_rows)
343
+ out.table(%w[name version status runners actors], group_rows)
318
344
  end
319
345
  end
320
346
 
@@ -81,8 +81,6 @@ module Legion
81
81
  build_actors
82
82
  build_hooks
83
83
  build_routes
84
- register_hooks
85
- register_routes
86
84
  Legion::Logging.debug "[Core] autobuild complete: #{name}" if defined?(Legion::Logging)
87
85
  end
88
86
 
@@ -216,14 +214,6 @@ module Legion
216
214
  {}
217
215
  end
218
216
 
219
- def register_hooks
220
- # Hook registration is handled by Routes::LexDispatch via the Router (v3.0)
221
- end
222
-
223
- def register_routes
224
- # Route registration is handled by Routes::LexDispatch via the Router (v3.0)
225
- end
226
-
227
217
  def auto_generate_transport
228
218
  require 'legion/extensions/transport'
229
219
  log.debug 'running meta magic to generate a transport base class'
@@ -38,66 +38,6 @@ module Legion
38
38
  end
39
39
  end
40
40
 
41
- # @deprecated Use definition DSL instead: definition :method, desc:, inputs:, outputs:
42
- def function_example(function, example)
43
- function_set(function, :example, example)
44
- end
45
-
46
- # @deprecated Use definition DSL instead: definition :method, inputs: { ... }
47
- def function_options(function, options)
48
- function_set(function, :options, options)
49
- end
50
-
51
- # @deprecated Use definition DSL instead: definition :method, desc: '...'
52
- def function_desc(function, desc)
53
- function_set(function, :desc, desc)
54
- end
55
-
56
- # @deprecated Use definition DSL instead: definition :method, outputs: { ... }
57
- def function_outputs(function, outputs)
58
- function_set(function, :outputs, outputs)
59
- end
60
-
61
- # @deprecated Use definition DSL instead: definition :method, category: '...'
62
- def function_category(function, category)
63
- function_set(function, :category, category)
64
- end
65
-
66
- # @deprecated Use definition DSL instead: definition :method, tags: [...]
67
- def function_tags(function, tags)
68
- function_set(function, :tags, tags)
69
- end
70
-
71
- # @deprecated Use definition DSL instead: definition :method, risk_tier: :standard
72
- def function_risk_tier(function, tier)
73
- function_set(function, :risk_tier, tier)
74
- end
75
-
76
- # @deprecated Use definition DSL instead: definition :method, idempotent: true
77
- def function_idempotent(function, value)
78
- function_set(function, :idempotent, value)
79
- end
80
-
81
- # @deprecated Use definition DSL instead: definition :method, requires: [...]
82
- def function_requires(function, deps)
83
- function_set(function, :requires, deps)
84
- end
85
-
86
- # @deprecated Use definition DSL instead: definition :method, mcp_exposed: true
87
- def function_expose(function, value)
88
- function_set(function, :expose, value)
89
- end
90
-
91
- def function_set(function, key, value)
92
- unless respond_to? function
93
- log.debug "function_#{key} called but function doesn't exist, f: #{function}"
94
- return nil
95
- end
96
- settings[:functions] = {} if settings[:functions].nil?
97
- settings[:functions][function] = {} if settings[:functions][function].nil?
98
- settings[:functions][function][key] = value
99
- end
100
-
101
41
  def runner_desc(desc)
102
42
  settings[:runners] = {} if settings[:runners].nil?
103
43
  settings[:runners][actor_name.to_sym] = {} if settings[:runners][actor_name.to_sym].nil?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Legion
4
- VERSION = '1.6.26'
4
+ VERSION = '1.6.29'
5
5
  end
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.26
4
+ version: 1.6.29
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity