legionio 1.5.23 → 1.6.0
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 +9 -0
- data/CLAUDE.md +12 -11
- data/README.md +56 -19
- data/lib/legion/cli/knowledge_command.rb +193 -0
- data/lib/legion/cli/setup_command.rb +38 -0
- data/lib/legion/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6413e545fabb634ddda16a99e884701751aa1cdd8245b649799f4836ae0c7360
|
|
4
|
+
data.tar.gz: 4239fd5af0278ba21cf33bbd320e62e67b103d93d36f3f5266eb5269019b7859
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2dee1932ef724c587ff8d26c496913cb7b90b1385f7793b3d13c7e3e703440c0b6ad4f7b431215c395ee742cd920afebcda784e29feca058d67a6afb73cb0abb
|
|
7
|
+
data.tar.gz: fd476599db94cf729ed3e5b66f82f1f090b44215222c24e6a8cf8e6d67c9837fd204561c6054f83505b0fc194a3766aef365eadaa46712babb5750dde82383c3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Legion Changelog
|
|
2
2
|
|
|
3
|
+
## [1.6.0] - 2026-03-26
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `legion knowledge monitor add/list/remove/status` — multi-directory corpus monitor management
|
|
7
|
+
- `legion knowledge capture commit` — capture git commit as knowledge (hook-compatible)
|
|
8
|
+
- `legion knowledge capture session` — capture session summary as knowledge (hook-compatible)
|
|
9
|
+
- `legion setup claude-code` now installs write-back hooks for automatic knowledge capture
|
|
10
|
+
- `resolve_corpus_path` falls back to first registered monitor when no explicit path given
|
|
11
|
+
|
|
3
12
|
## [1.5.23] - 2026-03-26
|
|
4
13
|
|
|
5
14
|
### Changed
|
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.
|
|
12
|
+
**Version**: 1.6.0
|
|
13
13
|
**License**: Apache-2.0
|
|
14
14
|
**Docker**: `legionio/legion`
|
|
15
15
|
**Ruby**: >= 3.4
|
|
@@ -47,12 +47,13 @@ Legion.start
|
|
|
47
47
|
├── 6. setup_data (legion-data, MySQL/SQLite + migrations, optional)
|
|
48
48
|
├── 7. setup_rbac (legion-rbac, optional)
|
|
49
49
|
├── 8. setup_llm (legion-llm, AI provider setup + routing, optional)
|
|
50
|
-
├── 9.
|
|
51
|
-
├── 10.
|
|
52
|
-
├── 11.
|
|
53
|
-
├── 12.
|
|
54
|
-
├── 13.
|
|
55
|
-
|
|
50
|
+
├── 9. setup_apollo (legion-apollo, shared + local knowledge store, optional)
|
|
51
|
+
├── 10. setup_gaia (legion-gaia, cognitive coordination layer, optional)
|
|
52
|
+
├── 11. setup_telemetry (OpenTelemetry, optional)
|
|
53
|
+
├── 12. setup_supervision (process supervision)
|
|
54
|
+
├── 13. load_extensions (two-phase parallel: require+autobuild on FixedThreadPool, then hook_all_actors)
|
|
55
|
+
├── 14. Legion::Crypt.cs (distribute cluster secret)
|
|
56
|
+
└── 15. setup_api (start Sinatra/Puma on port 4567)
|
|
56
57
|
```
|
|
57
58
|
|
|
58
59
|
Each phase calls `Legion::Readiness.mark_ready(:component)`. All phases are individually toggleable via `Service.new(transport: false, ...)`.
|
|
@@ -150,7 +151,7 @@ Legion (lib/legion.rb)
|
|
|
150
151
|
│ # Populated by Builders::Routes during autobuild
|
|
151
152
|
│
|
|
152
153
|
├── MCP (legion-mcp gem) # Extracted to standalone gem — see legion-mcp/CLAUDE.md
|
|
153
|
-
│ └── (
|
|
154
|
+
│ └── (58 tools, 2 resources, TierRouter, PatternStore, ContextGuard, Observer, EmbeddingIndex)
|
|
154
155
|
│
|
|
155
156
|
├── DigitalWorker # Digital worker platform (AI-as-labor governance)
|
|
156
157
|
│ ├── Lifecycle # Worker state machine (active/paused/retired/terminated)
|
|
@@ -194,7 +195,7 @@ Legion (lib/legion.rb)
|
|
|
194
195
|
│ ├── Session # Multi-turn chat session with streaming
|
|
195
196
|
│ ├── SessionStore # Persistent session save/load/list/resume/fork
|
|
196
197
|
│ ├── Permissions # Tool permission model (interactive/auto_approve/read_only)
|
|
197
|
-
│ ├── ToolRegistry # Chat tool discovery and registration (40 built-in + extension tools)
|
|
198
|
+
│ ├── ToolRegistry # Chat tool discovery and registration (40 built-in tools + extension tools)
|
|
198
199
|
│ ├── ExtensionTool # permission_tier DSL module for LEX chat tools (:read/:write/:shell)
|
|
199
200
|
│ ├── ExtensionToolLoader # Lazy discovery of tools/ directories from loaded extensions
|
|
200
201
|
│ ├── Context # Project awareness (git, language, instructions, extra dirs)
|
|
@@ -480,7 +481,7 @@ legion
|
|
|
480
481
|
|
|
481
482
|
### MCP Design
|
|
482
483
|
|
|
483
|
-
Extracted to the `legion-mcp` gem (v0.5.
|
|
484
|
+
Extracted to the `legion-mcp` gem (v0.5.9). See `legion-mcp/CLAUDE.md` for full architecture.
|
|
484
485
|
|
|
485
486
|
- `Legion::MCP.server` is memoized singleton — call `Legion::MCP.reset!` in tests
|
|
486
487
|
- Tool naming: `legion.snake_case_name` (dot namespace, not slash)
|
|
@@ -768,7 +769,7 @@ rack-test, rake, rspec, rubocop, rubocop-rspec, simplecov
|
|
|
768
769
|
|
|
769
770
|
```bash
|
|
770
771
|
bundle install
|
|
771
|
-
bundle exec rspec #
|
|
772
|
+
bundle exec rspec # ~3500+ examples, 0 failures
|
|
772
773
|
bundle exec rubocop # 0 offenses
|
|
773
774
|
```
|
|
774
775
|
|
data/README.md
CHANGED
|
@@ -8,13 +8,13 @@ Schedule tasks, chain services into dependency graphs, run them concurrently via
|
|
|
8
8
|
╭──────────────────────────────────────╮
|
|
9
9
|
│ L E G I O N I O │
|
|
10
10
|
│ │
|
|
11
|
-
│ 280+ extensions ·
|
|
11
|
+
│ 280+ extensions · 58 MCP tools │
|
|
12
12
|
│ AI chat CLI · REST API · HA │
|
|
13
13
|
│ cognitive architecture · Vault │
|
|
14
14
|
╰──────────────────────────────────────╯
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
**Ruby >= 3.4** | **v1.
|
|
17
|
+
**Ruby >= 3.4** | **v1.5.20** | **Apache-2.0** | [@Esity](https://github.com/Esity)
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
@@ -33,7 +33,7 @@ When A completes, B runs. B triggers C, D, and E in parallel. Conditions gate ex
|
|
|
33
33
|
But that's just the foundation. LegionIO is also:
|
|
34
34
|
|
|
35
35
|
- **An AI coding assistant** — interactive chat with tools, code review, commit messages, PR generation, and multi-agent workflows
|
|
36
|
-
- **An MCP server** —
|
|
36
|
+
- **An MCP server** — 58 tools that let any AI agent run tasks, manage extensions, and query your infrastructure
|
|
37
37
|
- **A cognitive computing platform** — 242 brain-modeled extensions across 18 cognitive domains
|
|
38
38
|
- **A digital worker platform** — AI-as-labor with governance, risk tiers, and cost tracking
|
|
39
39
|
|
|
@@ -49,7 +49,7 @@ For the AI features:
|
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
51
|
legion # launch the interactive TTY shell
|
|
52
|
-
legion chat # interactive AI REPL with
|
|
52
|
+
legion chat # interactive AI REPL with 40 built-in tools
|
|
53
53
|
legion commit # AI-generated commit message from staged changes
|
|
54
54
|
legion review # AI code review of your code
|
|
55
55
|
```
|
|
@@ -162,7 +162,7 @@ legion chat prompt "explain main.rb" # single-prompt mode
|
|
|
162
162
|
echo "fix the bug" | legion chat prompt - # pipe from stdin
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
-
**
|
|
165
|
+
**40 built-in tools**: read_file, write_file, edit_file, search_files, search_content, run_command, save_memory, search_memory, web_search, spawn_agent, search_traces, query_knowledge, ingest_knowledge, consolidate_memory, relate_knowledge, knowledge_maintenance, knowledge_stats, summarize_traces, list_extensions, manage_tasks, system_status, view_events, cost_summary, reflect, manage_schedules, worker_status, detect_anomalies, view_trends, trigger_dream, generate_insights, budget_status, provider_health, model_comparison, shadow_eval_status, entity_extract, arbitrage_status, escalation_status, graph_explore, scheduling_status, memory_status
|
|
166
166
|
|
|
167
167
|
**Slash commands**: `/help` `/quit` `/cost` `/status` `/clear` `/new` `/save` `/load` `/sessions` `/compact` `/fetch URL` `/search QUERY` `/diff` `/copy` `/rewind` `/memory` `/agent` `/agents` `/plan` `/swarm` `/review` `/permissions` `/personality` `/model` `/edit` `/commit` `/workers` `/dream`
|
|
168
168
|
|
|
@@ -200,6 +200,39 @@ legion memory search "testing"
|
|
|
200
200
|
legion memory forget 3
|
|
201
201
|
```
|
|
202
202
|
|
|
203
|
+
### Knowledge
|
|
204
|
+
|
|
205
|
+
Query and manage the Apollo shared knowledge store and local knowledge index:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
legion knowledge query "how does transport routing work?"
|
|
209
|
+
legion knowledge retrieve "embedding cosine similarity" --scope global
|
|
210
|
+
legion knowledge ingest /path/to/docs/
|
|
211
|
+
legion knowledge status # index stats, embedding coverage
|
|
212
|
+
legion knowledge health # detect orphans, quality metrics
|
|
213
|
+
legion knowledge maintain # cleanup orphans, reindex
|
|
214
|
+
legion knowledge quality # quality report
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Mind Growth
|
|
218
|
+
|
|
219
|
+
Autonomous cognitive architecture expansion system. Analyzes gaps, proposes new cognitive extensions, and builds them via a staged pipeline:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
legion mind-growth status # current growth cycle state
|
|
223
|
+
legion mind-growth analyze # gap analysis against 5 reference models
|
|
224
|
+
legion mind-growth propose # propose a new concept
|
|
225
|
+
legion mind-growth evaluate <id> # evaluate a proposal
|
|
226
|
+
legion mind-growth build <id> # run staged build pipeline
|
|
227
|
+
legion mind-growth list # list proposals
|
|
228
|
+
legion mind-growth approve <id> # manually approve
|
|
229
|
+
legion mind-growth reject <id> # manually reject
|
|
230
|
+
legion mind-growth profile # cognitive profile across all models
|
|
231
|
+
legion mind-growth health # extension fitness validation
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Requires `lex-mind-growth`. Also exposes 6 MCP tools in the `legion.mind_growth_*` namespace.
|
|
235
|
+
|
|
203
236
|
### Digital Workers
|
|
204
237
|
|
|
205
238
|
AI-as-labor with governance, risk tiers, and cost tracking:
|
|
@@ -326,7 +359,7 @@ legion mcp http # streamable HTTP on localhost:9393
|
|
|
326
359
|
legion mcp http --port 8080 --host 0.0.0.0
|
|
327
360
|
```
|
|
328
361
|
|
|
329
|
-
**
|
|
362
|
+
**58 tools** in the `legion.*` namespace:
|
|
330
363
|
|
|
331
364
|
| Category | Tools |
|
|
332
365
|
|----------|-------|
|
|
@@ -340,6 +373,8 @@ legion mcp http --port 8080 --host 0.0.0.0
|
|
|
340
373
|
| **Workers** | `list_workers`, `show_worker`, `worker_lifecycle`, `worker_costs`, `team_summary` |
|
|
341
374
|
| **RBAC** | `rbac_assignments`, `rbac_check`, `rbac_grants` |
|
|
342
375
|
| **Analytics** | `routing_stats` |
|
|
376
|
+
| **Knowledge** | `query_knowledge`, `knowledge_health` |
|
|
377
|
+
| **Mind Growth** | `mind_growth_status`, `mind_growth_analyze`, `mind_growth_propose`, `mind_growth_evaluate`, `mind_growth_build`, `mind_growth_profile` |
|
|
343
378
|
|
|
344
379
|
**Resources**: `legion://runners` (full runner catalog), `legion://extensions/{name}` (extension detail)
|
|
345
380
|
|
|
@@ -475,19 +510,21 @@ Before any Legion code loads, the executable applies three performance optimizat
|
|
|
475
510
|
```
|
|
476
511
|
legion start
|
|
477
512
|
└── Legion::Service
|
|
478
|
-
├── 1.
|
|
479
|
-
├── 2.
|
|
480
|
-
├── 3.
|
|
481
|
-
├── 4.
|
|
482
|
-
├── 5.
|
|
483
|
-
├── 6.
|
|
484
|
-
├── 7.
|
|
485
|
-
├── 8.
|
|
486
|
-
├── 9.
|
|
487
|
-
├── 10.
|
|
488
|
-
├── 11.
|
|
489
|
-
├── 12.
|
|
490
|
-
|
|
513
|
+
├── 1. Logging (legion-logging)
|
|
514
|
+
├── 2. Settings (legion-settings — /etc/legionio, ~/legionio, ./settings)
|
|
515
|
+
├── 3. Crypt (legion-crypt — Vault connection)
|
|
516
|
+
├── 4. Transport (legion-transport — RabbitMQ)
|
|
517
|
+
├── 5. Cache (legion-cache — Redis/Memcached)
|
|
518
|
+
├── 6. Data (legion-data — database + migrations)
|
|
519
|
+
├── 7. RBAC (legion-rbac — optional role-based access control)
|
|
520
|
+
├── 8. LLM (legion-llm — AI provider setup + routing)
|
|
521
|
+
├── 9. Apollo (legion-apollo — shared/local knowledge store)
|
|
522
|
+
├── 10. GAIA (legion-gaia — cognitive coordination layer)
|
|
523
|
+
├── 11. Telemetry (OpenTelemetry — optional)
|
|
524
|
+
├── 12. Supervision (process supervision)
|
|
525
|
+
├── 13. Extensions (two-phase parallel load: require+autobuild, then hook_all_actors)
|
|
526
|
+
├── 14. Cluster Secret (distribute via Vault or memory)
|
|
527
|
+
└── 15. API (Sinatra/Puma on port 4567)
|
|
491
528
|
```
|
|
492
529
|
|
|
493
530
|
Each phase registers with `Legion::Readiness`. All phases are individually toggleable.
|
|
@@ -2,6 +2,184 @@
|
|
|
2
2
|
|
|
3
3
|
module Legion
|
|
4
4
|
module CLI
|
|
5
|
+
class MonitorCommand < Thor
|
|
6
|
+
def self.exit_on_failure?
|
|
7
|
+
true
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class_option :json, type: :boolean, default: false, desc: 'Output as JSON'
|
|
11
|
+
class_option :no_color, type: :boolean, default: false, desc: 'Disable color output'
|
|
12
|
+
|
|
13
|
+
desc 'add PATH', 'Add a directory to corpus monitors'
|
|
14
|
+
option :extensions, type: :string, desc: 'Comma-separated file extensions to watch (e.g. md,rb)'
|
|
15
|
+
option :label, type: :string, desc: 'Human-readable label for this monitor'
|
|
16
|
+
def add(path)
|
|
17
|
+
require_monitor!
|
|
18
|
+
exts = options[:extensions]&.split(',')&.map(&:strip)
|
|
19
|
+
result = Legion::Extensions::Knowledge::Runners::Monitor.add_monitor(
|
|
20
|
+
path: path,
|
|
21
|
+
extensions: exts,
|
|
22
|
+
label: options[:label]
|
|
23
|
+
)
|
|
24
|
+
out = formatter
|
|
25
|
+
if options[:json]
|
|
26
|
+
out.json(result)
|
|
27
|
+
elsif result[:success]
|
|
28
|
+
out.success("Monitor added: #{path}")
|
|
29
|
+
else
|
|
30
|
+
out.warn("Failed to add monitor: #{result[:error]}")
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
desc 'list', 'List registered corpus monitors'
|
|
35
|
+
def list
|
|
36
|
+
require_monitor!
|
|
37
|
+
monitors = Legion::Extensions::Knowledge::Runners::Monitor.list_monitors
|
|
38
|
+
out = formatter
|
|
39
|
+
if options[:json]
|
|
40
|
+
out.json(monitors)
|
|
41
|
+
elsif monitors.nil? || monitors.empty?
|
|
42
|
+
out.warn('No monitors registered')
|
|
43
|
+
else
|
|
44
|
+
out.header('Knowledge Monitors')
|
|
45
|
+
monitors.each do |m|
|
|
46
|
+
label = m[:label] ? " [#{m[:label]}]" : ''
|
|
47
|
+
exts = m[:extensions]&.join(', ')
|
|
48
|
+
puts " #{m[:path]}#{label}"
|
|
49
|
+
puts " Extensions: #{exts}" if exts && !exts.empty?
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
default_task :list
|
|
54
|
+
|
|
55
|
+
desc 'remove IDENTIFIER', 'Remove a corpus monitor by path or label'
|
|
56
|
+
def remove(identifier)
|
|
57
|
+
require_monitor!
|
|
58
|
+
result = Legion::Extensions::Knowledge::Runners::Monitor.remove_monitor(identifier:)
|
|
59
|
+
out = formatter
|
|
60
|
+
if options[:json]
|
|
61
|
+
out.json(result)
|
|
62
|
+
elsif result[:success]
|
|
63
|
+
out.success("Monitor removed: #{identifier}")
|
|
64
|
+
else
|
|
65
|
+
out.warn("Failed to remove monitor: #{result[:error]}")
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
desc 'status', 'Show monitor status (counts)'
|
|
70
|
+
def status
|
|
71
|
+
require_monitor!
|
|
72
|
+
result = Legion::Extensions::Knowledge::Runners::Monitor.monitor_status
|
|
73
|
+
out = formatter
|
|
74
|
+
if options[:json]
|
|
75
|
+
out.json(result)
|
|
76
|
+
else
|
|
77
|
+
out.header('Monitor Status')
|
|
78
|
+
out.detail({
|
|
79
|
+
'Total monitors' => result[:total_monitors].to_s,
|
|
80
|
+
'Total files' => result[:total_files].to_s
|
|
81
|
+
})
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
no_commands do
|
|
86
|
+
def formatter
|
|
87
|
+
@formatter ||= Output::Formatter.new(json: options[:json], color: !options[:no_color])
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def require_monitor!
|
|
91
|
+
return if defined?(Legion::Extensions::Knowledge::Runners::Monitor)
|
|
92
|
+
|
|
93
|
+
raise CLI::Error, 'lex-knowledge extension is not loaded. Install and enable it first.'
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
class CaptureCommand < Thor
|
|
99
|
+
def self.exit_on_failure?
|
|
100
|
+
true
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
class_option :json, type: :boolean, default: false, desc: 'Output as JSON'
|
|
104
|
+
class_option :no_color, type: :boolean, default: false, desc: 'Disable color output'
|
|
105
|
+
|
|
106
|
+
desc 'commit', 'Capture the last git commit as knowledge'
|
|
107
|
+
def commit
|
|
108
|
+
log_line = `git log -1 --format='%H %s' 2>/dev/null`.strip
|
|
109
|
+
diff_stat = `git diff HEAD~1 --stat 2>/dev/null`.strip
|
|
110
|
+
|
|
111
|
+
if log_line.empty?
|
|
112
|
+
formatter.warn('No git commit found')
|
|
113
|
+
return
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
sha, *subject_parts = log_line.split
|
|
117
|
+
subject = subject_parts.join(' ')
|
|
118
|
+
content = "Git commit: #{sha}\nSubject: #{subject}\n\nDiff stat:\n#{diff_stat}"
|
|
119
|
+
tags = %w[git commit knowledge-capture]
|
|
120
|
+
|
|
121
|
+
result = if defined?(Legion::Extensions::Knowledge::Runners::Ingest)
|
|
122
|
+
Legion::Extensions::Knowledge::Runners::Ingest.ingest_file(
|
|
123
|
+
content: content,
|
|
124
|
+
tags: tags,
|
|
125
|
+
source: "git:#{sha}"
|
|
126
|
+
)
|
|
127
|
+
else
|
|
128
|
+
{ success: false, error: 'lex-knowledge not loaded' }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
out = formatter
|
|
132
|
+
if options[:json]
|
|
133
|
+
out.json(result)
|
|
134
|
+
elsif result[:success]
|
|
135
|
+
out.success("Captured commit #{sha[0, 8]}: #{subject}")
|
|
136
|
+
else
|
|
137
|
+
out.warn("Capture failed: #{result[:error]}")
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
desc 'session', 'Capture a session note from stdin'
|
|
142
|
+
def session
|
|
143
|
+
input = $stdin.gets(nil) if $stdin.ready? rescue nil # rubocop:disable Style/RescueModifier
|
|
144
|
+
input = input.to_s.strip
|
|
145
|
+
|
|
146
|
+
if input.empty?
|
|
147
|
+
formatter.warn('No session input provided (pipe text to stdin)')
|
|
148
|
+
return
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
repo = `git rev-parse --show-toplevel 2>/dev/null`.strip.split('/').last
|
|
152
|
+
content = "Session note (#{::Time.now.strftime('%Y-%m-%d')}):\n\n#{input}"
|
|
153
|
+
tags = ['session', 'knowledge-capture', ::Time.now.strftime('%Y-%m-%d')]
|
|
154
|
+
tags << "repo:#{repo}" unless repo.empty?
|
|
155
|
+
|
|
156
|
+
result = if defined?(Legion::Extensions::Knowledge::Runners::Ingest)
|
|
157
|
+
Legion::Extensions::Knowledge::Runners::Ingest.ingest_file(
|
|
158
|
+
content: content,
|
|
159
|
+
tags: tags,
|
|
160
|
+
source: "session:#{::Time.now.iso8601}"
|
|
161
|
+
)
|
|
162
|
+
else
|
|
163
|
+
{ success: false, error: 'lex-knowledge not loaded' }
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
out = formatter
|
|
167
|
+
if options[:json]
|
|
168
|
+
out.json(result)
|
|
169
|
+
elsif result[:success]
|
|
170
|
+
out.success('Session captured')
|
|
171
|
+
else
|
|
172
|
+
out.warn("Capture failed: #{result[:error]}")
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
no_commands do
|
|
177
|
+
def formatter
|
|
178
|
+
@formatter ||= Output::Formatter.new(json: options[:json], color: !options[:no_color])
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
5
183
|
class Knowledge < Thor
|
|
6
184
|
def self.exit_on_failure?
|
|
7
185
|
true
|
|
@@ -161,6 +339,12 @@ module Legion
|
|
|
161
339
|
end
|
|
162
340
|
end
|
|
163
341
|
|
|
342
|
+
desc 'monitor SUBCOMMAND', 'Manage knowledge corpus monitors'
|
|
343
|
+
subcommand 'monitor', MonitorCommand
|
|
344
|
+
|
|
345
|
+
desc 'capture SUBCOMMAND', 'Capture knowledge from git commits or sessions'
|
|
346
|
+
subcommand 'capture', CaptureCommand
|
|
347
|
+
|
|
164
348
|
no_commands do # rubocop:disable Metrics/BlockLength
|
|
165
349
|
def formatter
|
|
166
350
|
@formatter ||= Output::Formatter.new(json: options[:json], color: !options[:no_color])
|
|
@@ -199,6 +383,9 @@ module Legion
|
|
|
199
383
|
def resolve_corpus_path
|
|
200
384
|
if options[:corpus_path]
|
|
201
385
|
options[:corpus_path]
|
|
386
|
+
elsif defined?(Legion::Extensions::Knowledge::Runners::Monitor)
|
|
387
|
+
monitors = Legion::Extensions::Knowledge::Runners::Monitor.resolve_monitors
|
|
388
|
+
monitors.first&.dig(:path) || legacy_corpus_path || ::Dir.pwd
|
|
202
389
|
elsif defined?(Legion::Settings)
|
|
203
390
|
Legion::Settings.dig(:knowledge, :corpus_path) || ::Dir.pwd
|
|
204
391
|
else
|
|
@@ -206,6 +393,12 @@ module Legion
|
|
|
206
393
|
end
|
|
207
394
|
end
|
|
208
395
|
|
|
396
|
+
def legacy_corpus_path
|
|
397
|
+
return unless defined?(Legion::Settings)
|
|
398
|
+
|
|
399
|
+
Legion::Settings.dig(:knowledge, :corpus_path)
|
|
400
|
+
end
|
|
401
|
+
|
|
209
402
|
def print_sources(sources, out, verbose:)
|
|
210
403
|
return out.warn('No sources found') if sources.empty?
|
|
211
404
|
|
|
@@ -78,6 +78,7 @@ module Legion
|
|
|
78
78
|
|
|
79
79
|
install_claude_mcp(installed)
|
|
80
80
|
install_claude_skill(installed)
|
|
81
|
+
install_claude_hooks(installed)
|
|
81
82
|
|
|
82
83
|
if options[:json]
|
|
83
84
|
out.json(platform: 'claude-code', installed: installed)
|
|
@@ -343,6 +344,43 @@ module Legion
|
|
|
343
344
|
puts " Wrote slash command skill to #{skill_path}" unless options[:json]
|
|
344
345
|
end
|
|
345
346
|
|
|
347
|
+
def install_claude_hooks(installed)
|
|
348
|
+
settings_path = File.expand_path('~/.claude/settings.json')
|
|
349
|
+
existing = load_json_file(settings_path)
|
|
350
|
+
|
|
351
|
+
hooks = existing['hooks'] || {}
|
|
352
|
+
|
|
353
|
+
has_commit = Array(hooks['PostToolUse']).any? { |h| h['command']&.include?('knowledge capture commit') }
|
|
354
|
+
has_session = Array(hooks['Stop']).any? { |h| h['command']&.include?('knowledge capture session') }
|
|
355
|
+
if has_commit && has_session && !options[:force]
|
|
356
|
+
puts ' Write-back hooks already present (use --force to overwrite)' unless options[:json]
|
|
357
|
+
return
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
hooks['PostToolUse'] ||= []
|
|
361
|
+
hooks['Stop'] ||= []
|
|
362
|
+
|
|
363
|
+
unless has_commit
|
|
364
|
+
hooks['PostToolUse'] << {
|
|
365
|
+
'matcher' => 'Bash',
|
|
366
|
+
'command' => 'legionio knowledge capture commit',
|
|
367
|
+
'timeout' => 10_000
|
|
368
|
+
}
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
unless has_session
|
|
372
|
+
hooks['Stop'] << {
|
|
373
|
+
'command' => 'legionio knowledge capture session',
|
|
374
|
+
'timeout' => 15_000
|
|
375
|
+
}
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
existing['hooks'] = hooks
|
|
379
|
+
write_json_file(settings_path, existing)
|
|
380
|
+
installed << 'hooks'
|
|
381
|
+
puts ' Installed write-back hooks for knowledge capture' unless options[:json]
|
|
382
|
+
end
|
|
383
|
+
|
|
346
384
|
def write_mcp_servers_json(_out, path, installed)
|
|
347
385
|
existing = load_json_file(path)
|
|
348
386
|
servers = existing['mcpServers'] || {}
|
data/lib/legion/version.rb
CHANGED