Module: Esp::Introspection
- Defined in:
- lib/esp/introspection.rb
Overview
Builds a structured snapshot of the CLI command tree and the core library modules. Two consumers:
-
‘esp docs build` renders this into markdown under docs/reference/.
-
‘esp docs introspect` emits it as JSON so AI tools, ESPresso, and the MCP server can discover capabilities at runtime.
The introspection is read-only and cheap — it just walks Thor’s metadata and reads each lib/esp/,mw/*.rb header comment block.
Constant Summary collapse
- HIDDEN_COMMANDS =
%w[help tree].freeze
Class Method Summary collapse
- .command_tree ⇒ Object
-
.module_docs ⇒ Object
Modules documented in docs/reference/api/.
-
.parse_header_comment(path) ⇒ Object
Comment block immediately preceding the primary class/module declaration in ‘path`.
- .walk(thor_class, path) ⇒ Object
Class Method Details
.command_tree ⇒ Object
15 16 17 |
# File 'lib/esp/introspection.rb', line 15 def command_tree walk(Esp::CLI, []) end |
.module_docs ⇒ Object
Modules documented in docs/reference/api/. Walks both the engine-agnostic shell (lib/esp/*.rb → Esp::Foo) and the active Mw plugin (lib/esp/mw/*.rb → Esp::Mw::Foo). Skips cli.rb (the command reference covers it) and version.rb (trivial). The cli/ and providers/ subdirs are intentionally not walked here — they are subordinate to their parent modules and don’t warrant their own docs pages.
52 53 54 55 56 |
# File 'lib/esp/introspection.rb', line 52 def module_docs shell = Dir.glob(File.join(Esp::ROOT, 'lib/esp/*.rb')) plugin = Dir.glob(File.join(Esp::ROOT, 'lib/esp/mw/*.rb')) entries_for(shell, namespace: 'Esp') + entries_for(plugin, namespace: 'Esp::Mw') end |
.parse_header_comment(path) ⇒ Object
Comment block immediately preceding the primary class/module declaration in ‘path`. Strips leading `# ` from each line.
60 61 62 63 64 65 66 |
# File 'lib/esp/introspection.rb', line 60 def parse_header_comment(path) lines = File.readlines(path, chomp: true) target_idx = primary_declaration_index(lines) return nil unless target_idx collect_comment_above(lines, target_idx) end |
.walk(thor_class, path) ⇒ Object
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/esp/introspection.rb', line 19 def walk(thor_class, path) reverse_map = build_reverse_map(thor_class) subcommand_names = Array(thor_class.subcommands) commands = thor_class.commands.filter_map do |name, cmd| next if HIDDEN_COMMANDS.include?(name) || subcommand_names.include?(name) display = reverse_map[name.to_s] || name.to_s command_entry(display, path, cmd, thor_class) end subcommands = subcommand_names.map do |sub_name| sub_class = thor_class.subcommand_classes[sub_name] sub_walk = walk(sub_class, path + [sub_name]) { name: sub_name, path: path + [sub_name], description: thor_class.commands[sub_name]&.description, commands: sub_walk[:commands], subcommands: sub_walk[:subcommands] } end { commands: commands, subcommands: subcommands } end |