Class: KairosMcp::PluginProjector
- Inherits:
-
Object
- Object
- KairosMcp::PluginProjector
- Defined in:
- lib/kairos_mcp/plugin_projector.rb
Overview
Projects SkillSet plugin artifacts to Claude Code plugin/project structure.
Dual-mode:
:project (default) — writes to .claude/skills/, .claude/agents/, .claude/settings.json
:plugin — writes to plugin root skills/, agents/, hooks/hooks.json
Design: log/skillset_plugin_projection_design_v2.2_20260404.md
Constant Summary collapse
- SEED_SKILLS =
%w[kairos-chain].freeze
- PROJECTED_BY =
'kairos-chain'- SAFE_NAME_PATTERN =
/\A[a-zA-Z0-9][a-zA-Z0-9_-]*\z/- ALLOWED_HOOK_COMMANDS =
/\Akairos-/
Instance Attribute Summary collapse
-
#mode ⇒ Object
readonly
Returns the value of attribute mode.
-
#output_root ⇒ Object
readonly
Returns the value of attribute output_root.
-
#project_root ⇒ Object
readonly
Returns the value of attribute project_root.
Instance Method Summary collapse
-
#initialize(project_root, mode: :auto) ⇒ PluginProjector
constructor
A new instance of PluginProjector.
-
#project!(enabled_skillsets, knowledge_entries: []) ⇒ Object
Main entry: project all SkillSet plugin artifacts + L1 knowledge meta skill.
-
#project_if_changed!(enabled_skillsets, knowledge_entries: []) ⇒ Object
Digest-based no-op: skip projection if nothing changed.
-
#status ⇒ Object
Status summary for MCP tool.
-
#verify ⇒ Object
Verify projected files match manifest.
Constructor Details
#initialize(project_root, mode: :auto) ⇒ PluginProjector
Returns a new instance of PluginProjector.
25 26 27 28 29 30 |
# File 'lib/kairos_mcp/plugin_projector.rb', line 25 def initialize(project_root, mode: :auto) @project_root = project_root @mode = resolve_mode(mode) @output_root = @mode == :plugin ? project_root : File.join(project_root, '.claude') @manifest_path = File.join(project_root, '.kairos', 'projection_manifest.json') end |
Instance Attribute Details
#mode ⇒ Object (readonly)
Returns the value of attribute mode.
23 24 25 |
# File 'lib/kairos_mcp/plugin_projector.rb', line 23 def mode @mode end |
#output_root ⇒ Object (readonly)
Returns the value of attribute output_root.
23 24 25 |
# File 'lib/kairos_mcp/plugin_projector.rb', line 23 def output_root @output_root end |
#project_root ⇒ Object (readonly)
Returns the value of attribute project_root.
23 24 25 |
# File 'lib/kairos_mcp/plugin_projector.rb', line 23 def project_root @project_root end |
Instance Method Details
#project!(enabled_skillsets, knowledge_entries: []) ⇒ Object
Main entry: project all SkillSet plugin artifacts + L1 knowledge meta skill
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/kairos_mcp/plugin_projector.rb', line 33 def project!(enabled_skillsets, knowledge_entries: []) previous_manifest = load_manifest current_outputs = {} merged_hooks = @mode == :plugin ? load_seed_hooks : { 'hooks' => {} } enabled_skillsets.each do |ss| next unless ss.has_plugin? plugin_dir = File.join(ss.path, 'plugin') project_skill!(ss, plugin_dir, current_outputs) project_agents!(ss, plugin_dir, current_outputs) collect_hooks!(ss, plugin_dir, merged_hooks) end (knowledge_entries, current_outputs) write_merged_hooks!(merged_hooks, current_outputs) cleanup_stale!(previous_manifest, current_outputs) save_manifest(current_outputs, enabled_skillsets, knowledge_entries) end |
#project_if_changed!(enabled_skillsets, knowledge_entries: []) ⇒ Object
Digest-based no-op: skip projection if nothing changed
54 55 56 57 58 59 |
# File 'lib/kairos_mcp/plugin_projector.rb', line 54 def project_if_changed!(enabled_skillsets, knowledge_entries: []) digest = compute_source_digest(enabled_skillsets, knowledge_entries) return false if digest == load_manifest.dig('source_digest') project!(enabled_skillsets, knowledge_entries: knowledge_entries) true end |
#status ⇒ Object
Status summary for MCP tool
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/kairos_mcp/plugin_projector.rb', line 62 def status manifest = load_manifest { mode: @mode, output_root: @output_root, projected_at: manifest['projected_at'], source_digest: manifest['source_digest'], output_count: manifest.fetch('outputs', {}).size } end |
#verify ⇒ Object
Verify projected files match manifest
74 75 76 77 78 79 80 |
# File 'lib/kairos_mcp/plugin_projector.rb', line 74 def verify manifest = load_manifest outputs = manifest.fetch('outputs', {}) missing = outputs.keys.reject { |f| File.exist?(f) } orphaned = find_orphaned_files(outputs) { valid: missing.empty? && orphaned.empty?, missing: missing, orphaned: orphaned } end |