legionio 1.4.73 → 1.4.79
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/.github/workflows/ci.yml +13 -0
- data/CHANGELOG.md +63 -0
- data/CLAUDE.md +39 -45
- data/README.md +8 -6
- data/docs/plans/2026-03-19-hooks-expansion-design.md +211 -0
- data/legionio.gemspec +1 -1
- data/lib/legion/api/catalog.rb +82 -0
- data/lib/legion/api/hooks.rb +59 -28
- data/lib/legion/api/lex.rb +76 -0
- data/lib/legion/api/llm.rb +20 -2
- data/lib/legion/api/openapi.rb +89 -0
- data/lib/legion/api.rb +37 -8
- data/lib/legion/data/local_migrations/20260319000001_create_extension_catalog.rb +15 -0
- data/lib/legion/data/local_migrations/20260319000002_create_extension_permissions.rb +17 -0
- data/lib/legion/extensions/builders/hooks.rb +5 -1
- data/lib/legion/extensions/builders/routes.rb +66 -0
- data/lib/legion/extensions/builders/runners.rb +1 -0
- data/lib/legion/extensions/catalog.rb +102 -0
- data/lib/legion/extensions/core.rb +21 -1
- data/lib/legion/extensions/hooks/base.rb +5 -1
- data/lib/legion/extensions/permissions.rb +141 -0
- data/lib/legion/extensions.rb +8 -0
- data/lib/legion/version.rb +1 -1
- metadata +14 -53
- data/lib/legion/api/auth_kerberos.rb +0 -83
- data/lib/legion/api/oauth.rb +0 -39
- data/lib/legion/mcp/auth.rb +0 -50
- data/lib/legion/mcp/context_compiler.rb +0 -173
- data/lib/legion/mcp/embedding_index.rb +0 -113
- data/lib/legion/mcp/observer.rb +0 -135
- data/lib/legion/mcp/resources/extension_info.rb +0 -67
- data/lib/legion/mcp/resources/runner_catalog.rb +0 -63
- data/lib/legion/mcp/server.rb +0 -165
- data/lib/legion/mcp/tool_governance.rb +0 -77
- data/lib/legion/mcp/tools/create_chain.rb +0 -50
- data/lib/legion/mcp/tools/create_relationship.rb +0 -51
- data/lib/legion/mcp/tools/create_schedule.rb +0 -64
- data/lib/legion/mcp/tools/delete_chain.rb +0 -52
- data/lib/legion/mcp/tools/delete_relationship.rb +0 -52
- data/lib/legion/mcp/tools/delete_schedule.rb +0 -52
- data/lib/legion/mcp/tools/delete_task.rb +0 -49
- data/lib/legion/mcp/tools/describe_runner.rb +0 -92
- data/lib/legion/mcp/tools/disable_extension.rb +0 -50
- data/lib/legion/mcp/tools/discover_tools.rb +0 -53
- data/lib/legion/mcp/tools/do_action.rb +0 -55
- data/lib/legion/mcp/tools/enable_extension.rb +0 -50
- data/lib/legion/mcp/tools/get_config.rb +0 -63
- data/lib/legion/mcp/tools/get_extension.rb +0 -56
- data/lib/legion/mcp/tools/get_status.rb +0 -50
- data/lib/legion/mcp/tools/get_task.rb +0 -48
- data/lib/legion/mcp/tools/get_task_logs.rb +0 -56
- data/lib/legion/mcp/tools/list_chains.rb +0 -48
- data/lib/legion/mcp/tools/list_extensions.rb +0 -46
- data/lib/legion/mcp/tools/list_relationships.rb +0 -45
- data/lib/legion/mcp/tools/list_schedules.rb +0 -51
- data/lib/legion/mcp/tools/list_tasks.rb +0 -50
- data/lib/legion/mcp/tools/list_workers.rb +0 -53
- data/lib/legion/mcp/tools/rbac_assignments.rb +0 -45
- data/lib/legion/mcp/tools/rbac_check.rb +0 -45
- data/lib/legion/mcp/tools/rbac_grants.rb +0 -41
- data/lib/legion/mcp/tools/routing_stats.rb +0 -51
- data/lib/legion/mcp/tools/run_task.rb +0 -68
- data/lib/legion/mcp/tools/show_worker.rb +0 -48
- data/lib/legion/mcp/tools/team_summary.rb +0 -53
- data/lib/legion/mcp/tools/update_chain.rb +0 -54
- data/lib/legion/mcp/tools/update_relationship.rb +0 -55
- data/lib/legion/mcp/tools/update_schedule.rb +0 -65
- data/lib/legion/mcp/tools/worker_costs.rb +0 -55
- data/lib/legion/mcp/tools/worker_lifecycle.rb +0 -54
- data/lib/legion/mcp/usage_filter.rb +0 -86
- data/lib/legion/mcp.rb +0 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 833830caa5613e077d49c9a67c1dc00b907a473daf7be9033c9389c51546a5e3
|
|
4
|
+
data.tar.gz: 9c93197f8b0a9ecd0f784598c9b81e98d0158ab03b94d4b822a3d6ef55419868
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4689fa56cc6ad0cfd06f1b836fd36211edeaedacc65306ed888bdc97d36e1d430f5c7c6f3eb65427ff7c234cf1908f2fb14f26f448b8d6f2a414c726011c699f
|
|
7
|
+
data.tar.gz: 3a127117aba989a57d1e1077e6972a2d32d07c02148fb53eae5c083e8752d509d4a9d84a9db9bb3086292a983e3154d8632e7bca41483a5e9740ccb1769c1ec0
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -14,3 +14,16 @@ jobs:
|
|
|
14
14
|
uses: LegionIO/.github/.github/workflows/release.yml@main
|
|
15
15
|
secrets:
|
|
16
16
|
rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
|
|
17
|
+
|
|
18
|
+
trigger-homebrew:
|
|
19
|
+
needs: release
|
|
20
|
+
if: needs.release.outputs.changed == 'true'
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- name: Trigger daemon build
|
|
24
|
+
env:
|
|
25
|
+
GH_TOKEN: ${{ secrets.HOMEBREW_DISPATCH_TOKEN }}
|
|
26
|
+
run: |
|
|
27
|
+
gh api repos/LegionIO/homebrew-tap/dispatches \
|
|
28
|
+
-f event_type=build-daemon \
|
|
29
|
+
-f "client_payload[legionio_version]=${{ needs.release.outputs.version }}"
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
1
|
# Legion Changelog
|
|
2
2
|
|
|
3
|
+
## [1.4.79] - 2026-03-20
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Unified LEX routing layer: auto-expose runner functions as POST endpoints at `/api/lex/{ext}/{runner}/{action}`
|
|
7
|
+
- `Builders::Routes` auto-discovers runner public methods during extension autobuild
|
|
8
|
+
- `Routes::Lex` wildcard handler dispatches through Ingress with JWT + RBAC
|
|
9
|
+
- `GET /api/lex` listing endpoint for route discovery
|
|
10
|
+
- Settings-based configuration at `api.lex_routes` (global enable, per-extension enable, runner/function exclusions)
|
|
11
|
+
- `skip_routes` DSL for runner modules to opt out of auto-route exposure
|
|
12
|
+
- Auto-routes included in OpenAPI spec generation
|
|
13
|
+
- `runner_module` reference stored in builders runner hash for introspection
|
|
14
|
+
|
|
15
|
+
## [1.4.78] - 2026-03-19
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- Response headers support in `render_custom_response`: runners can return `response[:headers]` hash for custom HTTP headers
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
- Legacy `POST /api/hooks/:lex_name/:hook_name` route (superseded by `GET|POST /api/hooks/lex/*` splat routes in v1.4.76)
|
|
22
|
+
- Hardcoded `GET /api/auth/negotiate` Kerberos route (migrated to lex-kerberos hook at `/api/hooks/lex/kerberos/negotiate`)
|
|
23
|
+
- `Routes::AuthKerberos` module and `api/auth_kerberos.rb` file
|
|
24
|
+
|
|
25
|
+
## [1.4.77] - 2026-03-19
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
- Hardcoded deny list in `Extensions::Permissions` blocking access to `~/.ssh`, `~/.gnupg`, `~/.aws/credentials`
|
|
29
|
+
- Deny list overrides all other permission checks including explicit approvals
|
|
30
|
+
|
|
31
|
+
## [1.4.76] - 2026-03-19
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- `Hooks::Base.mount(path)` DSL for extension-derived URL suffixes (e.g., `/callback`)
|
|
35
|
+
- `GET /api/hooks/lex/*` splat route for hook discovery via GET requests
|
|
36
|
+
- `POST /api/hooks/lex/*` splat route with `route_path`-based hook dispatch
|
|
37
|
+
- `Legion::API.find_hook_by_path(path)` for direct route-path lookup in hook registry
|
|
38
|
+
- `route_path` field stored in hook registry entries and returned in `GET /api/hooks` listing
|
|
39
|
+
- Runner-controlled responses: `result[:response]` hash with `:status`, `:content_type`, `:body`
|
|
40
|
+
- `build_payload`, `dispatch_hook`, `render_custom_response` extracted helpers in Routes::Hooks
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- `register_hook` now accepts `route_path:` keyword; defaults to `lex_name/hook_name` if omitted
|
|
44
|
+
- `builders/hooks.rb` computes `route_path` from `extension_name/hook_name + mount_path`
|
|
45
|
+
- `extensions/core.rb` passes `route_path:` when calling `Legion::API.register_hook`
|
|
46
|
+
- `GET /api/hooks` listing now includes `route_path` and updated `endpoint` field
|
|
47
|
+
- Removed `Routes::OAuth` (moved OAuth callback to lex-microsoft_teams hook with mount path)
|
|
48
|
+
- `handle_hook_request` refactored into smaller helpers to stay within complexity limits
|
|
49
|
+
|
|
50
|
+
## [1.4.75] - 2026-03-19
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
- `Legion::Extensions::Catalog` singleton state machine tracking extension lifecycle (registered/loaded/starting/running/stopping/stopped)
|
|
54
|
+
- `Legion::Extensions::Permissions` three-layer file permission model (sandbox, declared paths, auto-approve globs)
|
|
55
|
+
- `GET /api/catalog` and `GET /api/catalog/:name` extension capability manifest endpoints
|
|
56
|
+
- Tier 0 routing in `POST /api/llm/chat` via `Legion::MCP::TierRouter` for LLM-free cached responses
|
|
57
|
+
- Data::Local migrations for extension_catalog and extension_permissions tables
|
|
58
|
+
- Catalog lifecycle wired into extension loader (register/loaded/running/stopping/stopped transitions)
|
|
59
|
+
|
|
60
|
+
## [1.4.74] - 2026-03-19
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
- Extracted `Legion::MCP` to dedicated `legion-mcp` gem (v0.1.0)
|
|
64
|
+
- Replaced `mcp` gem dependency with `legion-mcp`
|
|
65
|
+
|
|
3
66
|
## [1.4.73] - 2026-03-19
|
|
4
67
|
|
|
5
68
|
### Added
|
data/CLAUDE.md
CHANGED
|
@@ -9,7 +9,7 @@ The primary gem for the LegionIO framework. An extensible async job engine for s
|
|
|
9
9
|
|
|
10
10
|
**GitHub**: https://github.com/LegionIO/LegionIO
|
|
11
11
|
**Gem**: `legionio`
|
|
12
|
-
**Version**: 1.4.
|
|
12
|
+
**Version**: 1.4.79
|
|
13
13
|
**License**: Apache-2.0
|
|
14
14
|
**Docker**: `legionio/legion`
|
|
15
15
|
**Ruby**: >= 3.4
|
|
@@ -46,8 +46,8 @@ Legion.start
|
|
|
46
46
|
├── 5. require legion-cache
|
|
47
47
|
├── 6. setup_data (legion-data, MySQL/SQLite + migrations, optional)
|
|
48
48
|
├── 7. setup_rbac (legion-rbac, optional)
|
|
49
|
-
├── 8. setup_llm (legion-llm, optional)
|
|
50
|
-
├── 9. setup_gaia (legion-gaia, cognitive layer, optional)
|
|
49
|
+
├── 8. setup_llm (legion-llm, AI provider setup + routing, optional)
|
|
50
|
+
├── 9. setup_gaia (legion-gaia, cognitive coordination layer, optional)
|
|
51
51
|
├── 10. setup_telemetry (OpenTelemetry, optional)
|
|
52
52
|
├── 11. setup_supervision (process supervision)
|
|
53
53
|
├── 12. load_extensions (two-phase: require+autobuild all, then hook_all_actors)
|
|
@@ -95,9 +95,10 @@ Legion (lib/legion.rb)
|
|
|
95
95
|
│ │ └── Nothing # No-op actor
|
|
96
96
|
│ ├── Builders/ # Build actors and runners from LEX definitions
|
|
97
97
|
│ │ ├── Actors # Build actors from extension definitions
|
|
98
|
-
│ │ ├── Runners # Build runners from extension definitions
|
|
98
|
+
│ │ ├── Runners # Build runners from extension definitions (stores runner_module ref)
|
|
99
99
|
│ │ ├── Helpers # Builder utilities
|
|
100
|
-
│ │
|
|
100
|
+
│ │ ├── Hooks # Webhook hook system builder
|
|
101
|
+
│ │ └── Routes # Auto-route builder: introspects runners, registers POST /api/lex/* routes
|
|
101
102
|
│ ├── Helpers/ # Helper mixins for extensions
|
|
102
103
|
│ │ ├── Base # Base helper mixin
|
|
103
104
|
│ │ ├── Core # Core helper mixin
|
|
@@ -128,6 +129,7 @@ Legion (lib/legion.rb)
|
|
|
128
129
|
│ │ ├── Events # SSE stream (sinatra stream) + ring buffer polling fallback
|
|
129
130
|
│ │ ├── Transport # Connection status, exchanges, queues, publish
|
|
130
131
|
│ │ ├── Hooks # List + trigger registered extension hooks
|
|
132
|
+
│ │ ├── Lex # Auto-routes: `POST /api/lex/*` wildcard + `GET /api/lex` listing
|
|
131
133
|
│ │ ├── Workers # Digital worker lifecycle (`/api/workers/*`) + team routes (`/api/teams/*`)
|
|
132
134
|
│ │ ├── Coldstart # `POST /api/coldstart/ingest` — trigger lex-coldstart ingest from API
|
|
133
135
|
│ │ ├── Capacity # Aggregate, forecast, per-worker capacity endpoints
|
|
@@ -142,26 +144,13 @@ Legion (lib/legion.rb)
|
|
|
142
144
|
│ │ ├── ApiVersion # `/api/v1/` rewrite, Deprecation/Sunset headers
|
|
143
145
|
│ │ ├── BodyLimit # Request body size limit (1MB max, returns 413)
|
|
144
146
|
│ │ └── RateLimit # Sliding-window rate limiting with per-IP/agent/tenant tiers
|
|
145
|
-
│
|
|
146
|
-
│
|
|
147
|
+
│ ├── hook_registry # Class-level registry: register_hook, find_hook, registered_hooks
|
|
148
|
+
│ │ # Populated by extensions via Legion::API.register_hook(...)
|
|
149
|
+
│ └── route_registry # Class-level registry: register_route, find_route_by_path, registered_routes
|
|
150
|
+
│ # Populated by Builders::Routes during autobuild
|
|
147
151
|
│
|
|
148
|
-
├── MCP (mcp gem)
|
|
149
|
-
│
|
|
150
|
-
│ ├── Server # MCP::Server builder, tool/resource registration
|
|
151
|
-
│ ├── Tools/ # 35 MCP::Tool subclasses (legion.* namespace)
|
|
152
|
-
│ │ ├── RunTask # Agentic: dot notation task execution
|
|
153
|
-
│ │ ├── DescribeRunner # Agentic: runner/function discovery
|
|
154
|
-
│ │ ├── List/Get/Delete Task + GetTaskLogs
|
|
155
|
-
│ │ ├── List/Create/Update/Delete Chain
|
|
156
|
-
│ │ ├── List/Create/Update/Delete Relationship
|
|
157
|
-
│ │ ├── List/Get/Enable/Disable Extension
|
|
158
|
-
│ │ ├── List/Create/Update/Delete Schedule
|
|
159
|
-
│ │ ├── GetStatus, GetConfig
|
|
160
|
-
│ │ ├── ListWorkers, ShowWorker, WorkerLifecycle, WorkerCosts, TeamSummary, RoutingStats
|
|
161
|
-
│ │ └── RbacAssignments, RbacCheck, RbacGrants
|
|
162
|
-
│ └── Resources/
|
|
163
|
-
│ ├── RunnerCatalog # legion://runners - all ext.runner.func paths
|
|
164
|
-
│ └── ExtensionInfo # legion://extensions/{name} - extension detail template
|
|
152
|
+
├── MCP (legion-mcp gem) # Extracted to standalone gem — see legion-mcp/CLAUDE.md
|
|
153
|
+
│ └── (35 tools, 2 resources, TierRouter, PatternStore, ContextGuard, Observer, EmbeddingIndex)
|
|
165
154
|
│
|
|
166
155
|
├── DigitalWorker # Digital worker platform (AI-as-labor governance)
|
|
167
156
|
│ ├── Lifecycle # Worker state machine (active/paused/retired/terminated)
|
|
@@ -228,6 +217,10 @@ Legion (lib/legion.rb)
|
|
|
228
217
|
├── Pr # `legion pr` - AI-generated PR title and description via LLM
|
|
229
218
|
├── Review # `legion review` - AI code review with severity levels
|
|
230
219
|
├── Gaia # `legion gaia` - Gaia status
|
|
220
|
+
├── Llm # `legion llm` - LLM subsystem status and provider health
|
|
221
|
+
├── Detect # `legion detect scan` - scan environment and recommend extensions
|
|
222
|
+
├── Observe # `legion observe stats` - MCP tool usage statistics from Observer
|
|
223
|
+
├── Tty # `legion tty interactive` - launch rich terminal UI (legion-tty)
|
|
231
224
|
├── Graph # `legion graph show` - task relationship graph (mermaid/dot)
|
|
232
225
|
├── Trace # `legion trace search` - NL trace search via LLM
|
|
233
226
|
├── Dashboard # `legion dashboard` - TUI operational dashboard with auto-refresh
|
|
@@ -364,7 +357,7 @@ legion
|
|
|
364
357
|
|
|
365
358
|
plan # read-only exploration mode (no writes/edits/shell)
|
|
366
359
|
[--model MODEL] [--provider PROVIDER]
|
|
367
|
-
# Slash commands: /save (writes plan to docs/
|
|
360
|
+
# Slash commands: /save (writes plan to docs/work/planning/), /help, /quit
|
|
368
361
|
|
|
369
362
|
swarm # multi-agent workflow orchestration
|
|
370
363
|
start NAME # run a workflow from .legion/swarms/NAME.json
|
|
@@ -483,11 +476,11 @@ legion
|
|
|
483
476
|
|
|
484
477
|
### MCP Design
|
|
485
478
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
- HTTP transport uses rackup + puma
|
|
479
|
+
Extracted to the `legion-mcp` gem (v0.1.0). See `legion-mcp/CLAUDE.md` for full architecture.
|
|
480
|
+
|
|
489
481
|
- `Legion::MCP.server` is memoized singleton — call `Legion::MCP.reset!` in tests
|
|
490
482
|
- Tool naming: `legion.snake_case_name` (dot namespace, not slash)
|
|
483
|
+
- Tier 0 routing: PatternStore + TierRouter + ContextGuard for LLM-free cached responses
|
|
491
484
|
|
|
492
485
|
## Dependencies
|
|
493
486
|
|
|
@@ -507,7 +500,7 @@ legion
|
|
|
507
500
|
| `oj` (>= 3.16) | Fast JSON (C extension) |
|
|
508
501
|
| `puma` (>= 6.0) | HTTP server for API |
|
|
509
502
|
| `rackup` (>= 2.0) | Rack server launcher for MCP HTTP transport |
|
|
510
|
-
| `mcp`
|
|
503
|
+
| `legion-mcp` | MCP server + Tier 0 routing (extracted gem) |
|
|
511
504
|
| `reline` (>= 0.5) | Interactive line editing for chat REPL |
|
|
512
505
|
| `rouge` (>= 4.0) | Syntax highlighting for chat markdown rendering |
|
|
513
506
|
| `tty-spinner` (~> 0.9) | Spinner animation for CLI loading states |
|
|
@@ -539,7 +532,7 @@ rack-test, rake, rspec, rubocop, rubocop-rspec, simplecov
|
|
|
539
532
|
| `lib/legion/extensions.rb` | LEX discovery, loading, actor hooking, shutdown |
|
|
540
533
|
| `lib/legion/extensions/core.rb` | Extension mixin (requirement flags, autobuild) |
|
|
541
534
|
| `lib/legion/extensions/actors/` | Actor types: base, every, loop, once, poll, subscription, nothing, defaults |
|
|
542
|
-
| `lib/legion/extensions/builders/` | Build actors, runners, helpers, hooks from definitions |
|
|
535
|
+
| `lib/legion/extensions/builders/` | Build actors, runners, helpers, hooks, routes from definitions |
|
|
543
536
|
| `lib/legion/extensions/helpers/` | Mixins: base, core, cache, data, logger, transport, task, lex |
|
|
544
537
|
| `lib/legion/extensions/data/` | Extension-level migrator and model |
|
|
545
538
|
| `lib/legion/extensions/hooks/base.rb` | Webhook hook base class |
|
|
@@ -572,16 +565,19 @@ rack-test, rake, rspec, rubocop, rubocop-rspec, simplecov
|
|
|
572
565
|
| `lib/legion/api/settings.rb` | Settings: read/write with redaction + readonly guards |
|
|
573
566
|
| `lib/legion/api/events.rb` | Events: SSE stream + polling fallback (ring buffer) |
|
|
574
567
|
| `lib/legion/api/transport.rb` | Transport: status, exchanges, queues, publish |
|
|
575
|
-
| `lib/legion/api/hooks.rb` | Hooks: list registered + trigger via Ingress |
|
|
568
|
+
| `lib/legion/api/hooks.rb` | Hooks: list registered + trigger via Ingress; supports custom response headers |
|
|
569
|
+
| `lib/legion/api/lex.rb` | Lex auto-routes: `POST /api/lex/*` wildcard dispatch + `GET /api/lex` listing |
|
|
576
570
|
| `lib/legion/api/workers.rb` | Workers + Teams: digital worker lifecycle REST endpoints (`/api/workers/*`) and team cost endpoints (`/api/teams/*`) |
|
|
577
571
|
| `lib/legion/api/coldstart.rb` | Coldstart: `POST /api/coldstart/ingest` — triggers lex-coldstart ingest runner (requires lex-coldstart + lex-memory) |
|
|
578
572
|
| `lib/legion/api/gaia.rb` | Gaia: system status endpoints |
|
|
579
573
|
| `lib/legion/api/token.rb` | Token: JWT token issuance endpoint |
|
|
580
574
|
| `lib/legion/api/openapi.rb` | OpenAPI: `Legion::API::OpenAPI.spec` / `.to_json`; also served at `GET /api/openapi.json` |
|
|
581
|
-
| `lib/legion/api/oauth.rb` | OAuth: `GET /api/oauth/microsoft_teams/callback` — receives delegated OAuth redirect and stores tokens |
|
|
582
575
|
| `lib/legion/api/capacity.rb` | Capacity: aggregate, forecast, and per-worker capacity endpoints |
|
|
583
576
|
| `lib/legion/api/tenants.rb` | Tenants: listing, provisioning, suspension, quota check |
|
|
577
|
+
| `lib/legion/api/catalog.rb` | Catalog: extension catalog with metadata endpoints |
|
|
578
|
+
| `lib/legion/api/llm.rb` | LLM: provider status and routing configuration endpoints |
|
|
584
579
|
| `lib/legion/api/audit.rb` | Audit: list, show, count, export audit log entries |
|
|
580
|
+
| `lib/legion/api/auth.rb` | Auth: combined token exchange endpoint (`POST /api/auth/token` — JWKS verify + RBAC claims mapper) |
|
|
585
581
|
| `lib/legion/api/auth_human.rb` | Auth: human user authentication endpoints |
|
|
586
582
|
| `lib/legion/api/auth_worker.rb` | Auth: digital worker authentication endpoints |
|
|
587
583
|
| `lib/legion/api/rbac.rb` | RBAC: role listing, permission grants, access checks |
|
|
@@ -604,19 +600,12 @@ rack-test, rake, rspec, rubocop, rubocop-rspec, simplecov
|
|
|
604
600
|
| `lib/legion/tenant_context.rb` | Thread-local tenant context propagation (set, clear, with block) |
|
|
605
601
|
| `lib/legion/tenants.rb` | Tenant CRUD, suspension, quota enforcement |
|
|
606
602
|
| `lib/legion/capacity/model.rb` | Workforce capacity calculation (throughput, utilization, forecast, per-worker) |
|
|
607
|
-
| **MCP** | |
|
|
608
|
-
| `lib/legion/mcp.rb` | Entry point: `Legion::MCP.server` singleton factory, `server_for(token:)` |
|
|
609
|
-
| `lib/legion/mcp/auth.rb` | MCP authentication: JWT + API key verification |
|
|
610
|
-
| `lib/legion/mcp/tool_governance.rb` | Risk-tier tool filtering and invocation audit |
|
|
611
|
-
| `lib/legion/mcp/server.rb` | MCP::Server builder, TOOL_CLASSES array, governance-aware build |
|
|
603
|
+
| **MCP** (extracted to `legion-mcp` gem) | |
|
|
612
604
|
| `lib/legion/digital_worker.rb` | DigitalWorker module entry point |
|
|
613
605
|
| `lib/legion/digital_worker/lifecycle.rb` | Worker state machine |
|
|
614
606
|
| `lib/legion/digital_worker/registry.rb` | In-process worker registry |
|
|
615
607
|
| `lib/legion/digital_worker/risk_tier.rb` | AIRB risk tier + governance constraints |
|
|
616
608
|
| `lib/legion/digital_worker/value_metrics.rb` | Token/cost/latency tracking |
|
|
617
|
-
| `lib/legion/mcp/tools/` | 35 MCP::Tool subclasses (incl. rbac_assignments, rbac_check, rbac_grants) |
|
|
618
|
-
| `lib/legion/mcp/resources/runner_catalog.rb` | `legion://runners` resource |
|
|
619
|
-
| `lib/legion/mcp/resources/extension_info.rb` | `legion://extensions/{name}` resource template |
|
|
620
609
|
| **CLI v2** | |
|
|
621
610
|
| `lib/legion/cli.rb` | `Legion::CLI::Main` Thor app, global flags, version, start/stop/status/check |
|
|
622
611
|
| `lib/legion/cli/output.rb` | `Output::Formatter`: color, tables, JSON mode, ANSI stripping |
|
|
@@ -676,16 +665,23 @@ rack-test, rake, rspec, rubocop, rubocop-rspec, simplecov
|
|
|
676
665
|
| `lib/legion/cli/version.rb` | CLI version display helper |
|
|
677
666
|
| `lib/legion/docs/site_generator.rb` | Static documentation site generator |
|
|
678
667
|
| `lib/legion/cli/memory_command.rb` | `legion memory` subcommands (list, add, forget, search, clear) |
|
|
679
|
-
| `lib/legion/cli/plan_command.rb` | `legion plan` — read-only exploration mode with /save to docs/
|
|
668
|
+
| `lib/legion/cli/plan_command.rb` | `legion plan` — read-only exploration mode with /save to docs/work/planning/ |
|
|
680
669
|
| `lib/legion/cli/swarm_command.rb` | `legion swarm` — multi-agent workflow orchestration from `.legion/swarms/` |
|
|
681
670
|
| `lib/legion/cli/commit_command.rb` | `legion commit` — AI-generated commit messages via LLM |
|
|
682
671
|
| `lib/legion/cli/pr_command.rb` | `legion pr` — AI-generated PR title + description via LLM |
|
|
683
672
|
| `lib/legion/cli/review_command.rb` | `legion review` — AI code review with severity levels (CRITICAL/WARNING/SUGGESTION/NOTE) |
|
|
684
673
|
| `lib/legion/cli/gaia_command.rb` | `legion gaia` subcommands (status) |
|
|
674
|
+
| `lib/legion/cli/llm_command.rb` | `legion llm` subcommands (status) — LLM subsystem status and provider health |
|
|
675
|
+
| `lib/legion/cli/detect_command.rb` | `legion detect scan` — scan environment and recommend extensions |
|
|
676
|
+
| `lib/legion/cli/observe_command.rb` | `legion observe stats` — MCP tool usage statistics from Observer |
|
|
677
|
+
| `lib/legion/cli/tty_command.rb` | `legion tty interactive` — launch rich terminal UI (legion-tty interactive shell) |
|
|
678
|
+
| `lib/legion/cli/interactive.rb` | `Interactive` Thor class — shared CLI module for `legion` binary entry point |
|
|
679
|
+
| `lib/legion/cli/config_import.rb` | `legion config import` — import config from external sources |
|
|
685
680
|
| `lib/legion/cli/schedule_command.rb` | `legion schedule` subcommands (list, show, add, remove, logs) |
|
|
686
681
|
| `lib/legion/cli/completion_command.rb` | `legion completion` subcommands (bash, zsh, install) |
|
|
687
682
|
| `lib/legion/cli/openapi_command.rb` | `legion openapi` subcommands (generate, routes); also `GET /api/openapi.json` endpoint |
|
|
688
|
-
| `lib/legion/cli/doctor_command.rb` | `legion doctor` —
|
|
683
|
+
| `lib/legion/cli/doctor_command.rb` | `legion doctor` — 11-check environment diagnosis; `Doctor::Result` value object with status/message/prescription/auto_fixable |
|
|
684
|
+
| `lib/legion/cli/doctor/` | Individual check modules: ruby_version, bundle, config, rabbitmq, database, cache, vault, extensions, pid, permissions, plus result.rb |
|
|
689
685
|
| `lib/legion/cli/telemetry_command.rb` | `legion telemetry` subcommands (stats, ingest) — session log analytics |
|
|
690
686
|
| `lib/legion/cli/auth_command.rb` | `legion auth` subcommands (teams) — delegated OAuth browser flow for external services |
|
|
691
687
|
| `completions/legion.bash` | Bash tab completion script |
|
|
@@ -713,8 +709,6 @@ rack-test, rake, rspec, rubocop, rubocop-rspec, simplecov
|
|
|
713
709
|
| `API::Routes::Relationships` | Fully implemented (backed by legion-data migration 013) |
|
|
714
710
|
| `API::Routes::Chains` | 501 stub - no data model |
|
|
715
711
|
| `API::Middleware::Auth` | JWT Bearer auth middleware — real token validation and API key (`X-API-Key` header) auth both implemented |
|
|
716
|
-
| `MCP::Auth` | JWT + API key authentication for MCP server (HTTP transport) |
|
|
717
|
-
| `MCP::ToolGovernance` | Risk-tier tool filtering + audit — disabled by default, opt-in via settings |
|
|
718
712
|
| `legion-data` chains/relationships models | Not yet implemented |
|
|
719
713
|
|
|
720
714
|
## Rubocop Notes
|
|
@@ -728,7 +722,7 @@ rack-test, rake, rspec, rubocop, rubocop-rspec, simplecov
|
|
|
728
722
|
|
|
729
723
|
```bash
|
|
730
724
|
bundle install
|
|
731
|
-
bundle exec rspec #
|
|
725
|
+
bundle exec rspec # 1499 examples, 0 failures
|
|
732
726
|
bundle exec rubocop # 418 files, 0 offenses
|
|
733
727
|
```
|
|
734
728
|
|
data/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Schedule tasks, chain services into dependency graphs, run them concurrently via
|
|
|
14
14
|
╰──────────────────────────────────────╯
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
**Ruby >= 3.4** | **v1.4.
|
|
17
|
+
**Ruby >= 3.4** | **v1.4.78** | **Apache-2.0** | [@Esity](https://github.com/Esity)
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
@@ -461,11 +461,13 @@ legion start
|
|
|
461
461
|
├── 4. Transport (legion-transport — RabbitMQ)
|
|
462
462
|
├── 5. Cache (legion-cache — Redis/Memcached)
|
|
463
463
|
├── 6. Data (legion-data — database + migrations)
|
|
464
|
-
├── 7.
|
|
465
|
-
├── 8.
|
|
466
|
-
├── 9.
|
|
467
|
-
├── 10.
|
|
468
|
-
|
|
464
|
+
├── 7. RBAC (legion-rbac — optional role-based access control)
|
|
465
|
+
├── 8. LLM (legion-llm — AI provider setup + routing)
|
|
466
|
+
├── 9. GAIA (legion-gaia — cognitive coordination layer)
|
|
467
|
+
├── 10. Supervision (process supervision)
|
|
468
|
+
├── 11. Extensions (discover + load 280+ LEX gems, filtered by role profile)
|
|
469
|
+
├── 12. Cluster Secret (distribute via Vault or memory)
|
|
470
|
+
└── 13. API (Sinatra/Puma on port 4567)
|
|
469
471
|
```
|
|
470
472
|
|
|
471
473
|
Each phase registers with `Legion::Readiness`. All phases are individually toggleable.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# Hooks Expansion Design
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
Expand the existing hooks system to support GET + POST, extension-derived URL paths, and runner-controlled responses. Removes hardcoded extension routes from LegionIO (starting with `api/oauth.rb`) by letting extensions own their HTTP surface through the existing `hooks/` convention.
|
|
6
|
+
|
|
7
|
+
## Problem
|
|
8
|
+
|
|
9
|
+
Extensions that need HTTP endpoints (OAuth callbacks, webhooks, status pages) currently require hardcoded routes in LegionIO's `api/` directory. The `api/oauth.rb` file knows about Microsoft Teams specifically. This couples LegionIO to individual extensions and bypasses the Ingress pipeline (no RBAC, no audit, no events).
|
|
10
|
+
|
|
11
|
+
The hooks system already handles inbound webhooks with auto-discovery, verification DSL, and Ingress routing — but it only supports POST and always returns JSON.
|
|
12
|
+
|
|
13
|
+
## Approach
|
|
14
|
+
|
|
15
|
+
Expand the existing hooks infrastructure. No new module types, no new DSL classes. Three changes:
|
|
16
|
+
|
|
17
|
+
1. Add GET alongside POST in `api/hooks.rb`
|
|
18
|
+
2. Add a `mount` class method to `Hooks::Base` for sub-path suffixes
|
|
19
|
+
3. Add response control so runners can return HTML/redirects instead of JSON
|
|
20
|
+
|
|
21
|
+
## URL Derivation
|
|
22
|
+
|
|
23
|
+
The full URL is deterministic and non-overridable:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
/api/hooks/lex/{extension_name}/{hook_class_name}{mount_suffix}
|
|
27
|
+
fixed from module from class name optional DSL
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- `extension_name` — derived from Ruby module hierarchy. `Legion::Extensions::MicrosoftTeams` becomes `microsoft_teams`. Cannot be overridden.
|
|
31
|
+
- `hook_class_name` — derived from the hook class name. `Hooks::Auth` becomes `auth`. Cannot be overridden.
|
|
32
|
+
- `mount_suffix` — optional, declared via `mount '/callback'` in the hook class. Appended after the class name segment.
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
|
|
36
|
+
| Hook class | mount | URL |
|
|
37
|
+
|-----------|-------|-----|
|
|
38
|
+
| `MicrosoftTeams::Hooks::Auth` | `'/callback'` | `/api/hooks/lex/microsoft_teams/auth/callback` |
|
|
39
|
+
| `MicrosoftTeams::Hooks::Webhook` | none | `/api/hooks/lex/microsoft_teams/webhook` |
|
|
40
|
+
| `Github::Hooks::Push` | none | `/api/hooks/lex/github/push` |
|
|
41
|
+
| `Slack::Hooks::Events` | `'/interactive'` | `/api/hooks/lex/slack/events/interactive` |
|
|
42
|
+
|
|
43
|
+
The extension name prefix acts as a namespace fence — extensions can only define routes under their own name. No collisions.
|
|
44
|
+
|
|
45
|
+
## HTTP Method Support
|
|
46
|
+
|
|
47
|
+
Both GET and POST route to the same handler method. The runner receives a normalized request hash:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
{
|
|
51
|
+
http_method: 'GET',
|
|
52
|
+
params: { code: '...', state: '...' },
|
|
53
|
+
headers: { 'HTTP_HOST' => '...' },
|
|
54
|
+
body: nil
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
For GET requests, `params` comes from query string. For POST, `params` is the parsed body. `body` contains the raw POST body (needed for HMAC verification). `headers` are the Rack-normalized request headers.
|
|
59
|
+
|
|
60
|
+
The API handler:
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
app.get '/api/hooks/lex/:lex_name/*' do
|
|
64
|
+
handle_hook_request(params, request)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
app.post '/api/hooks/lex/:lex_name/*' do
|
|
68
|
+
handle_hook_request(params, request)
|
|
69
|
+
end
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Both call the same `handle_hook_request` private method that resolves the hook, verifies, and pipes through `Ingress.run`.
|
|
73
|
+
|
|
74
|
+
## Response Control
|
|
75
|
+
|
|
76
|
+
If the runner result hash contains a `:response` key, the API layer renders it directly. Otherwise, the default JSON task response.
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
# Runner returning a custom response (OAuth callback):
|
|
80
|
+
def auth_callback(code:, state:, **)
|
|
81
|
+
# ... token exchange logic ...
|
|
82
|
+
{
|
|
83
|
+
result: { authenticated: true },
|
|
84
|
+
response: {
|
|
85
|
+
status: 200,
|
|
86
|
+
content_type: 'text/html',
|
|
87
|
+
body: '<html><body><h2>Authentication complete</h2></body></html>'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
API handler logic:
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
result = Ingress.run(...)
|
|
97
|
+
if result[:response]
|
|
98
|
+
status result[:response][:status] || 200
|
|
99
|
+
content_type result[:response][:content_type] || 'application/json'
|
|
100
|
+
result[:response][:body]
|
|
101
|
+
else
|
|
102
|
+
json_response({ task_id: result[:task_id], status: result[:status] })
|
|
103
|
+
end
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The `result` key alongside `response` means the task system still captures the outcome for audit/logging even when the HTTP response is HTML. If `:response` is absent, behavior is identical to today.
|
|
107
|
+
|
|
108
|
+
## Hooks::Base Changes
|
|
109
|
+
|
|
110
|
+
One new class method:
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
class Base
|
|
114
|
+
class << self
|
|
115
|
+
def mount(path)
|
|
116
|
+
@mount_path = path
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
attr_reader :mount_path
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Existing DSL unchanged: `route_header`, `route_field`, `verify_hmac`, `verify_token` all still work. They operate on the request after URL routing, same as today.
|
|
125
|
+
|
|
126
|
+
For hooks that handle both GET callbacks and POST webhooks on the same path, the existing `route` method can inspect the HTTP method from the payload to decide which runner function to call. Or the runner can handle both in a single method.
|
|
127
|
+
|
|
128
|
+
## Builder Changes
|
|
129
|
+
|
|
130
|
+
`builders/hooks.rb` `build_hook_list` currently registers hooks keyed by `"lex_name/hook_name"`. Changes:
|
|
131
|
+
|
|
132
|
+
- Read `hook_class.mount_path` (nil if not declared)
|
|
133
|
+
- Build the full route path: `"{extension_name}/{hook_name}{mount_path}"`
|
|
134
|
+
- Store the full route path in the registry entry
|
|
135
|
+
|
|
136
|
+
`find_hook` changes to match against the request splat path instead of discrete lex_name/hook_name params.
|
|
137
|
+
|
|
138
|
+
## Hook Registry
|
|
139
|
+
|
|
140
|
+
Current registry on `Legion::API`:
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
register_hook(lex_name:, hook_name:, hook_class:, default_runner:)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Add `route_path:` to the registration:
|
|
147
|
+
|
|
148
|
+
```ruby
|
|
149
|
+
register_hook(lex_name:, hook_name:, hook_class:, default_runner:, route_path:)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`find_hook` changes from two-param lookup to splat-path matching:
|
|
153
|
+
|
|
154
|
+
```ruby
|
|
155
|
+
def find_hook_by_path(path)
|
|
156
|
+
hook_registry.values.find { |h| h[:route_path] == path }
|
|
157
|
+
end
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Backward Compatibility
|
|
161
|
+
|
|
162
|
+
- Hooks without `mount` work exactly as before — filename becomes the hook name, URL is `/api/hooks/lex/{ext}/{hook_name}`
|
|
163
|
+
- Old `POST /api/hooks/:lex_name/:hook_name` route stays as deprecated alias pointing to the new handler
|
|
164
|
+
- All existing `Hooks::Base` DSL works unchanged
|
|
165
|
+
- Extensions that don't define hooks are unaffected
|
|
166
|
+
|
|
167
|
+
## Migration: api/oauth.rb
|
|
168
|
+
|
|
169
|
+
The hardcoded Microsoft Teams OAuth callback moves to lex-microsoft_teams:
|
|
170
|
+
|
|
171
|
+
**New file:** `lex-microsoft_teams/hooks/auth.rb`
|
|
172
|
+
|
|
173
|
+
```ruby
|
|
174
|
+
class Auth < Legion::Extensions::Hooks::Base
|
|
175
|
+
mount '/callback'
|
|
176
|
+
end
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
**Runner method** in lex-microsoft_teams handles the callback: receives `code` and `state` params, emits the event, returns HTML response.
|
|
180
|
+
|
|
181
|
+
**LegionIO:** Remove `require_relative 'api/oauth'` and `register Routes::OAuth` from `api.rb`. Delete or gut `api/oauth.rb`.
|
|
182
|
+
|
|
183
|
+
## Testing
|
|
184
|
+
|
|
185
|
+
### LegionIO Specs
|
|
186
|
+
|
|
187
|
+
- Hooks::Base `mount` sets and reads mount_path
|
|
188
|
+
- Builder reads mount_path, builds correct route_path
|
|
189
|
+
- API handler resolves hook from splat path (GET and POST)
|
|
190
|
+
- API handler renders `:response` when present in runner result
|
|
191
|
+
- API handler returns default JSON when `:response` absent
|
|
192
|
+
- Backward compat: old `/api/hooks/:lex_name/:hook_name` still works
|
|
193
|
+
- Verification (HMAC, token) works on both GET and POST
|
|
194
|
+
|
|
195
|
+
### lex-microsoft_teams Specs
|
|
196
|
+
|
|
197
|
+
- Hook class discovered by builder
|
|
198
|
+
- OAuth callback runner handles code+state, returns HTML response
|
|
199
|
+
- Events emitted on successful callback
|
|
200
|
+
|
|
201
|
+
## Files Changed
|
|
202
|
+
|
|
203
|
+
| File | Repo | Change |
|
|
204
|
+
|------|------|--------|
|
|
205
|
+
| `extensions/hooks/base.rb` | LegionIO | Add `mount` class method |
|
|
206
|
+
| `extensions/builders/hooks.rb` | LegionIO | Read mount_path, build full route_path |
|
|
207
|
+
| `api/hooks.rb` | LegionIO | Add GET route, splat matching, `handle_hook_request`, response control |
|
|
208
|
+
| `api.rb` | LegionIO | Remove `Routes::OAuth`, add backward compat alias |
|
|
209
|
+
| `api/oauth.rb` | LegionIO | Delete |
|
|
210
|
+
| `hooks/auth.rb` | lex-microsoft_teams | New file |
|
|
211
|
+
| Runner (TBD) | lex-microsoft_teams | OAuth callback handler method |
|
data/legionio.gemspec
CHANGED
|
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
|
|
|
34
34
|
spec.bindir = 'exe'
|
|
35
35
|
spec.executables = %w[legion legionio]
|
|
36
36
|
|
|
37
|
-
spec.add_dependency 'mcp'
|
|
37
|
+
spec.add_dependency 'legion-mcp'
|
|
38
38
|
|
|
39
39
|
spec.add_dependency 'bootsnap', '>= 1.18'
|
|
40
40
|
spec.add_dependency 'concurrent-ruby', '>= 1.2'
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
class API < Sinatra::Base
|
|
5
|
+
module Routes
|
|
6
|
+
module ExtensionCatalog
|
|
7
|
+
def self.registered(app)
|
|
8
|
+
app.get '/api/catalog' do
|
|
9
|
+
entries = Legion::Extensions::Catalog.all.map do |name, entry|
|
|
10
|
+
build_catalog_manifest(name, entry)
|
|
11
|
+
end
|
|
12
|
+
json_response(entries)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
app.get '/api/catalog/:name' do
|
|
16
|
+
name = params[:name]
|
|
17
|
+
entry = Legion::Extensions::Catalog.entry(name)
|
|
18
|
+
unless entry
|
|
19
|
+
halt 404, { 'Content-Type' => 'application/json' },
|
|
20
|
+
Legion::JSON.dump({ error: { code: 'not_found', message: "Extension #{name} not found" } })
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
json_response(build_catalog_manifest(name, entry))
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
helpers do # rubocop:disable Metrics/BlockLength
|
|
30
|
+
def build_catalog_manifest(name, entry)
|
|
31
|
+
{
|
|
32
|
+
name: name,
|
|
33
|
+
state: entry[:state].to_s,
|
|
34
|
+
started_at: entry[:started_at]&.iso8601,
|
|
35
|
+
permissions: build_catalog_permissions(name),
|
|
36
|
+
runners: build_catalog_runners(name),
|
|
37
|
+
known_intents: build_catalog_known_intents(name)
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def build_catalog_permissions(name)
|
|
42
|
+
declared = Legion::Extensions::Permissions.declared_paths(name)
|
|
43
|
+
{
|
|
44
|
+
sandbox: Legion::Extensions::Permissions.sandbox_path(name),
|
|
45
|
+
read_paths: declared[:read_paths],
|
|
46
|
+
write_paths: declared[:write_paths]
|
|
47
|
+
}
|
|
48
|
+
rescue StandardError
|
|
49
|
+
{ sandbox: Legion::Extensions::Permissions.sandbox_path(name), read_paths: [], write_paths: [] }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def build_catalog_runners(name)
|
|
53
|
+
return {} unless defined?(Legion::Data) && Legion::Data.respond_to?(:connected?) && Legion::Data.connected?
|
|
54
|
+
|
|
55
|
+
ext = Legion::Data::Model::Extension.where(gem_name: name).first
|
|
56
|
+
return {} unless ext
|
|
57
|
+
|
|
58
|
+
ext.runners.to_h do |runner|
|
|
59
|
+
[runner.values[:name], {
|
|
60
|
+
methods: runner.functions.map { |f| f.values[:name] },
|
|
61
|
+
description: runner.values[:description]
|
|
62
|
+
}]
|
|
63
|
+
end
|
|
64
|
+
rescue StandardError
|
|
65
|
+
{}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def build_catalog_known_intents(name)
|
|
69
|
+
return [] unless defined?(Legion::MCP::PatternStore)
|
|
70
|
+
|
|
71
|
+
matched = Legion::MCP::PatternStore.patterns.select do |_hash, pattern|
|
|
72
|
+
pattern[:tool_chain]&.any? { |t| t.start_with?(name) }
|
|
73
|
+
end
|
|
74
|
+
matched.map do |_hash, pattern|
|
|
75
|
+
{ intent: pattern[:intent_text], tool_chain: pattern[:tool_chain], confidence: pattern[:confidence] }
|
|
76
|
+
end
|
|
77
|
+
rescue StandardError
|
|
78
|
+
[]
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|