Module: Space::Architect::CLI

Defined in:
lib/space_architect/cli.rb,
lib/space_architect/cli/src.rb,
lib/space_architect/cli/space.rb,
lib/space_architect/cli/research.rb,
lib/space_architect/cli/architect.rb

Defined Under Namespace

Modules: Architect, Registry

Constant Summary collapse

Outcome =

Delegate the outcome seam to Space::Core::CLI so both architect commands (which call CLI.record_outcome lexically) and the moved Helpers (which call CLI.record_outcome with Space::Core::CLI as lexical root) share one slot.

Space::Core::CLI::Outcome
Helpers =
Space::Core::CLI::Helpers
BaseCommand =
Space::Core::CLI::BaseCommand
TOP_LEVEL_HELP =
[[], ["--help"], ["-h"], ["help"]].freeze
VERSION_REQUEST =
[["version"], ["--version"]].freeze

Class Method Summary collapse

Class Method Details

.call(argv, out = $stdout, err = $stderr) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/space_architect/cli.rb', line 26

def self.call(argv, out = $stdout, err = $stderr)
  Thread.current[:space_core_cli_outcome] = nil
  Space::Core::CLI.help_pastel = Pastel.new(enabled: Space::Core::CLI.help_colors?(argv, out, err))

  if TOP_LEVEL_HELP.include?(argv)
    out.puts Dry::CLI::Usage.call(Registry.get([]))
    return 0
  end

  if VERSION_REQUEST.include?(argv)
    out.puts Space::Core::VERSION
    return 0
  end

  if argv.first == "src"
    return dispatch_src(argv[1..], out, err)
  end

  normalized = normalize_args(argv)

  if normalized.first == "space"
    return dispatch_space(normalized[1..], out, err)
  end

  Dry::CLI.new(Registry).call(arguments: normalized, out: out, err: err)
  last_outcome&.exit_code || 0
end

.dispatch_space(rest, out = $stdout, err = $stderr) ⇒ Object

Exit-code bridge to the Space::Core CLI engine. ‘architect space <args>` (and `exe/space <args>` via Space::Core::CLI directly) hands the raw remainder to Space::Core’s own dry-cli registry and translates Space::Core’s recorded Outcome into the host exit code. Space::Core has its own Registry, Outcome, and :space_core_cli_outcome thread-local; this is the seam between the two registries (NOT a re-registration).



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/space_architect/cli/space.rb', line 13

def self.dispatch_space(rest, out = $stdout, err = $stderr)
  if ::Space::Core::CLI::TOP_LEVEL_HELP.include?(rest)
    out.puts Dry::CLI::Usage.call(::Space::Core::CLI::Registry.get([]))
    return 0
  end

  if ::Space::Core::CLI::VERSION_REQUEST.include?(rest)
    out.puts ::Space::Core::VERSION
    return 0
  end

  Thread.current[:space_core_cli_outcome] = nil
  Dry::CLI.new(::Space::Core::CLI::Registry).call(arguments: rest, out: out, err: err)
  ::Space::Core::CLI.last_outcome&.exit_code || 0
end

.dispatch_src(rest, out = $stdout, err = $stderr) ⇒ Object

Exit-code bridge to the Space::Src CLI engine. ‘architect src <args>` hands the raw remainder to Space::Src’s own dry-cli registry and translates Space::Src’s recorded Outcome into the host exit code. Space::Src has its own Registry, Outcome, and :space_src_cli_* thread-locals; this is the seam between the two registries (NOT a re-registration). Space::Src’s top-level help/version interceptors call Kernel.exit, so we reproduce that interception here against the injected IO instead of delegating to them. dry-cli’s internal exit on a bare group / unknown command propagates as SystemExit — same as the host’s own bare groups (e.g. ‘space repo`) — and is intentionally NOT rescued (accepted behavior change).



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/space_architect/cli/src.rb', line 17

def self.dispatch_src(rest, out = $stdout, err = $stderr)
  if ::Space::Src::CLI::TOP_LEVEL_HELP.include?(rest)
    out.puts Dry::CLI::Usage.call(::Space::Src::CLI::Registry.get([]))
    return 0
  end
  if ::Space::Src::CLI::VERSION_REQUEST.include?(rest)
    out.puts ::Space::Src::VERSION
    return 0
  end

  if ::Space::Src::CLI.bare_query?(rest)
    paths = ::Space::Src::CLI.make_paths
    config = ::Space::Src::Config::Store.load(paths.config_file).success
    return ::Space::Src::Nav.dispatch(rest[0], out, err, config.base_dir)
  end

  Thread.current[:space_src_cli_outcome] = nil
  Dry::CLI.new(::Space::Src::CLI::Registry).call(arguments: rest, out: out, err: err)
  ::Space::Src::CLI.last_outcome&.exit_code || 0
end

.last_outcomeObject



17
# File 'lib/space_architect/cli.rb', line 17

def self.last_outcome      = Space::Core::CLI.last_outcome

.normalize_args(argv) ⇒ Object

Move –color/–colors options to the end of the argument list so dry-cli’s command routing is not confused by options before the subcommand name.

Two passes:

1. Leading: extract two-token form (--color VALUE) and =-form from the
   front while args still look like options.
2. Non-leading: extract =-form (--color=VALUE / --colors=VALUE) from any
   position before the -- separator. The bare two-token form is ambiguous
   with a subcommand name in non-leading position and is left in place.


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/space_architect/cli.rb', line 63

def self.normalize_args(argv)
  args = argv.dup
  extracted = []

  # Pass 1: leading two-token and =-form (existing behavior, unchanged)
  while (arg = args.first) && arg != "--" && arg.start_with?("-")
    if %w[--color --colors].include?(arg)
      extracted << args.shift
      extracted << args.shift if args.first && !args.first.start_with?("-")
    elsif arg.start_with?("--color=", "--colors=")
      extracted << args.shift
    else
      break
    end
  end

  # Pass 2: =-form from any non-leading position, stop at --
  sep = args.index("--")
  head = sep ? args[0, sep] : args
  tail = sep ? args[sep..] : []
  mid_color, head = head.partition { |a| a.start_with?("--color=", "--colors=") }
  extracted += mid_color
  args = head + tail

  extracted.empty? ? args : args + extracted
end

.record_outcome(o) ⇒ Object



16
# File 'lib/space_architect/cli.rb', line 16

def self.record_outcome(o) = Space::Core::CLI.record_outcome(o)

.run(argv, out = $stdout, err = $stderr) ⇒ Object



90
91
92
93
94
95
# File 'lib/space_architect/cli.rb', line 90

def self.run(argv, out = $stdout, err = $stderr)
  Kernel.exit(call(argv, out, err))
rescue Interrupt
  err.puts "interrupted"
  Kernel.exit(130)
end