Class: Textus::CLI::Verb
- Inherits:
-
Object
- Object
- Textus::CLI::Verb
- Defined in:
- lib/textus/cli/verb.rb,
lib/textus/cli/verb/get.rb,
lib/textus/cli/verb/put.rb,
lib/textus/cli/verb/boot.rb,
lib/textus/cli/verb/init.rb,
lib/textus/cli/verb/build.rb,
lib/textus/cli/verb/fetch.rb,
lib/textus/cli/verb/hooks.rb,
lib/textus/cli/verb/doctor.rb,
lib/textus/cli/verb/hook_run.rb,
lib/textus/cli/verb/fetch_all.rb,
lib/textus/cli/verb/mcp_serve.rb,
lib/textus/cli/verb/schema_diff.rb,
lib/textus/cli/verb/schema_init.rb,
lib/textus/cli/verb/schema_migrate.rb
Overview
Subclasses must implement #call(store) and return an integer exit code. Use #emit(obj) for normal JSON output (returns 0). Subclasses that don’t need a Textus store (e.g. Init) override ‘.needs_store?` to return false; dispatch will pass nil instead.
Direct Known Subclasses
Group, Runner::Base, Boot, Doctor, Fetch, FetchAll, HookRun, Hooks, Init, MCPServe, SchemaDiff, SchemaInit, SchemaMigrate
Defined Under Namespace
Classes: Boot, Build, Doctor, Fetch, FetchAll, Get, HookRun, Hooks, Init, MCPServe, Put, SchemaDiff, SchemaInit, SchemaMigrate
Instance Attribute Summary collapse
-
#positional ⇒ Object
readonly
Returns the value of attribute positional.
-
#stdin ⇒ Object
readonly
The input stream — the source for a ‘cli_stdin` envelope (ADR 0068).
Class Method Summary collapse
-
.command_name(name = nil) ⇒ Object
Declarative CLI name.
-
.descendants ⇒ Object
Recursive subclass enumeration.
- .inherited(subclass) ⇒ Object
- .needs_store? ⇒ Boolean
- .option(name, optspec) ⇒ Object
- .options ⇒ Object
-
.parent_group(group_klass = nil) ⇒ Object
Declares that this verb is a subcommand of ‘group_klass`.
Instance Method Summary collapse
-
#context_for(store) ⇒ Object
Returns a Call value bound to the resolved role.
-
#emit(obj, exit_code: 0) ⇒ Object
Hashes get “protocol” => PROTOCOL prepended unless they already carry one (Store envelopes do).
-
#initialize(stdin:, stdout:, stderr:, cwd: nil) ⇒ Verb
constructor
A new instance of Verb.
- #parse(argv) ⇒ Object
-
#resolved_role(store, default: Role::DEFAULT) ⇒ Object
Resolves the active role for this invocation.
-
#session_for(store) ⇒ Object
Returns a RoleScope bound to the resolved role.
Constructor Details
#initialize(stdin:, stdout:, stderr:, cwd: nil) ⇒ Verb
Returns a new instance of Verb.
61 62 63 64 65 66 |
# File 'lib/textus/cli/verb.rb', line 61 def initialize(stdin:, stdout:, stderr:, cwd: nil) @stdin = stdin @stdout = stdout @stderr = stderr @cwd = cwd end |
Instance Attribute Details
#positional ⇒ Object (readonly)
Returns the value of attribute positional.
82 83 84 |
# File 'lib/textus/cli/verb.rb', line 82 def positional @positional end |
#stdin ⇒ Object (readonly)
The input stream — the source for a ‘cli_stdin` envelope (ADR 0068).
113 114 115 |
# File 'lib/textus/cli/verb.rb', line 113 def stdin @stdin end |
Class Method Details
.command_name(name = nil) ⇒ Object
Declarative CLI name. Reader returns the registered name (or nil for verbs that aren’t directly invokable, like the abstract Verb/Group base classes). Writer registers it.
28 29 30 31 32 33 34 |
# File 'lib/textus/cli/verb.rb', line 28 def command_name(name = nil) if name.nil? @command_name else @command_name = name.to_s end end |
.descendants ⇒ Object
Recursive subclass enumeration. Ruby 3.1 ships Class#subclasses but not Class#descendants, so we expand it ourselves.
56 57 58 |
# File 'lib/textus/cli/verb.rb', line 56 def descendants subclasses.flat_map { |k| [k] + k.descendants } end |
.inherited(subclass) ⇒ Object
47 48 49 50 51 52 |
# File 'lib/textus/cli/verb.rb', line 47 def inherited(subclass) super subclass.instance_variable_set(:@options, []) subclass.instance_variable_set(:@command_name, nil) subclass.instance_variable_set(:@parent_group, nil) end |
.needs_store? ⇒ Boolean
21 22 23 |
# File 'lib/textus/cli/verb.rb', line 21 def needs_store? true end |
.option(name, optspec) ⇒ Object
12 13 14 15 |
# File 'lib/textus/cli/verb.rb', line 12 def option(name, optspec) << [name, optspec] attr_accessor(name) end |
.options ⇒ Object
17 18 19 |
# File 'lib/textus/cli/verb.rb', line 17 def @options ||= [] end |
.parent_group(group_klass = nil) ⇒ Object
Declares that this verb is a subcommand of ‘group_klass`. When set, the verb is NOT a top-level CLI verb — it’s listed under the group’s subcommands instead.
39 40 41 42 43 44 45 |
# File 'lib/textus/cli/verb.rb', line 39 def parent_group(group_klass = nil) if group_klass.nil? @parent_group else @parent_group = group_klass end end |
Instance Method Details
#context_for(store) ⇒ Object
Returns a Call value bound to the resolved role. Convenience for verbs whose only pre-call boilerplate is resolving the role and wrapping it in a Call.
103 104 105 |
# File 'lib/textus/cli/verb.rb', line 103 def context_for(store) Textus::Call.build(role: resolved_role(store)) end |
#emit(obj, exit_code: 0) ⇒ Object
Hashes get “protocol” => PROTOCOL prepended unless they already carry one (Store envelopes do). Caller’s value wins on collision.
86 87 88 89 90 |
# File 'lib/textus/cli/verb.rb', line 86 def emit(obj, exit_code: 0) payload = obj.is_a?(Hash) ? { "protocol" => PROTOCOL }.merge(obj) : obj @stdout.puts(JSON.generate(payload)) exit_code end |
#parse(argv) ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/textus/cli/verb.rb', line 68 def parse(argv) fmt = "json" OptionParser.new do |o| self.class..each do |name, optspec| o.on(optspec) { |v| public_send(:"#{name}=", v) } end o.on("--output=FMT") { |v| fmt = v } o.on("--format=FMT") { |_v| raise FlagRenamed.new("--format", "--output") } end.permute!(argv) raise UsageError.new("only --output=json is supported in v1") unless fmt == "json" @positional = argv.dup end |
#resolved_role(store, default: Role::DEFAULT) ⇒ Object
Resolves the active role for this invocation. Honors the verb’s ‘–as` flag if declared, then TEXTUS_ROLE, then the project default. Pass `default:` to override the fallback (e.g. MCPServe uses AGENT).
95 96 97 98 |
# File 'lib/textus/cli/verb.rb', line 95 def resolved_role(store, default: Role::DEFAULT) flag = respond_to?(:as_flag) ? as_flag : nil Role.resolve(flag: flag, env: ENV, root: store.root, default: default) end |
#session_for(store) ⇒ Object
Returns a RoleScope bound to the resolved role.
108 109 110 |
# File 'lib/textus/cli/verb.rb', line 108 def session_for(store) store.as(resolved_role(store)) end |