space-architect 1.3.0 → 2.0.0.rc2
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 +103 -0
- data/README.md +267 -158
- data/exe/architect +1 -1
- data/exe/space +2 -2
- data/exe/src +13 -0
- data/lib/space_architect/{architect_mission.rb → architect_project.rb} +475 -125
- data/lib/space_architect/cli/architect.rb +248 -178
- data/lib/space_architect/cli/research.rb +94 -0
- data/lib/space_architect/cli/space.rb +25 -31
- data/lib/space_architect/cli/src.rb +20 -14
- data/lib/space_architect/cli.rb +22 -22
- data/lib/space_architect/dispatcher.rb +5 -1
- data/lib/space_architect/gate_evaluator.rb +65 -0
- data/lib/space_architect/gate_lint.rb +140 -0
- data/lib/space_architect/harness.rb +145 -17
- data/lib/space_architect/research/mux.rb +127 -0
- data/lib/space_architect/research/registry.rb +70 -0
- data/lib/space_architect/research/renderer.rb +101 -0
- data/lib/space_architect/research/run.rb +7 -0
- data/lib/space_architect/research/supervisor.rb +108 -0
- data/lib/space_architect/research.rb +13 -0
- data/lib/space_architect/run_creator.rb +53 -0
- data/lib/space_architect/skill_installer.rb +81 -79
- data/lib/space_architect/templates/architect.md.erb +15 -4
- data/lib/space_architect/templates/brief.md.erb +5 -5
- data/lib/space_architect/templates/iteration.md.erb +17 -6
- data/lib/space_architect.rb +8 -21
- data/lib/{space_architect → space_core}/atomic_write.rb +1 -1
- data/lib/space_core/cli/base_command.rb +19 -0
- data/lib/space_core/cli/build.rb +27 -0
- data/lib/space_core/cli/config.rb +49 -0
- data/lib/space_core/cli/current.rb +16 -0
- data/lib/space_core/cli/help.rb +123 -0
- data/lib/space_core/cli/helpers.rb +115 -0
- data/lib/space_core/cli/init.rb +29 -0
- data/lib/space_core/cli/list.rb +24 -0
- data/lib/space_core/cli/new.rb +38 -0
- data/lib/space_core/cli/pack.rb +29 -0
- data/lib/space_core/cli/path.rb +16 -0
- data/lib/space_core/cli/repeatable_options.rb +75 -0
- data/lib/space_core/cli/repo.rb +76 -0
- data/lib/space_core/cli/run.rb +29 -0
- data/lib/space_core/cli/shell.rb +125 -0
- data/lib/space_core/cli/show.rb +21 -0
- data/lib/space_core/cli/status.rb +33 -0
- data/lib/space_core/cli/use.rb +17 -0
- data/lib/space_core/cli.rb +177 -0
- data/lib/{space_architect → space_core}/config.rb +1 -1
- data/lib/{space_architect → space_core}/errors.rb +1 -1
- data/lib/{space_architect → space_core}/git_client.rb +1 -1
- data/lib/{space_architect → space_core}/mise_client.rb +1 -1
- data/lib/space_core/oci_builder.rb +56 -0
- data/lib/space_core/oci_packer.rb +99 -0
- data/lib/space_core/oci_runner.rb +73 -0
- data/lib/{space_architect → space_core}/repo_reference.rb +1 -1
- data/lib/{space_architect → space_core}/repo_resolver.rb +1 -1
- data/lib/{space_architect → space_core}/shell_integration.rb +1 -1
- data/lib/{space_architect → space_core}/slugger.rb +1 -1
- data/lib/{space_architect → space_core}/space.rb +11 -3
- data/lib/{space_architect → space_core}/space_store.rb +13 -13
- data/lib/{space_architect → space_core}/state.rb +1 -1
- data/lib/space_core/templates/oci/dockerfile.erb +63 -0
- data/lib/space_core/templates/oci/dockerignore.erb +17 -0
- data/lib/space_core/templates/oci/entrypoint.sh.erb +10 -0
- data/lib/{space_architect → space_core}/terminal.rb +1 -1
- data/lib/space_core/version.rb +7 -0
- data/lib/{space_architect → space_core}/warnings.rb +1 -1
- data/lib/{space_architect → space_core}/xdg.rb +1 -1
- data/lib/space_core.rb +24 -0
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/clone.rb +5 -5
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/config.rb +7 -7
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/daemon.rb +46 -30
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/options.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/org.rb +9 -9
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/repo.rb +9 -9
- data/lib/space_src/cli/shell.rb +122 -0
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/status.rb +7 -7
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli/sync.rb +17 -17
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cli.rb +42 -11
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/cloner.rb +3 -3
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/contract.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/duration.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/model.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/config/store.rb +5 -5
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/forge/client.rb +2 -2
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/forge/github.rb +4 -4
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/launchd/agent.rb +5 -5
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/launchd/plist.rb +3 -3
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/log_rotator.rb +1 -1
- data/lib/space_src/migration.rb +43 -0
- data/lib/space_src/nav.rb +98 -0
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/paths.rb +2 -2
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/scm/client.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/scm/git.rb +4 -4
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/scm/status.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/shell.rb +1 -1
- data/lib/space_src/shell_integration.rb +321 -0
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/state/lock.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/state/store.rb +2 -2
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/sync/engine.rb +12 -12
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/sync/repo_plan.rb +3 -3
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/interactive_reporter.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/json_reporter.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/mode.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/plain_reporter.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/ui/reporter.rb +1 -1
- data/{vendor/repo-tender/lib/space_architect/pristine → lib/space_src}/version.rb +2 -2
- data/lib/space_src.rb +37 -0
- data/skill/architect/SKILL.md +110 -54
- data/skill/architect/dispatch.md +147 -39
- data/skill/architect/research.md +46 -37
- data/skill/architect-research/SKILL.md +2 -2
- data/skill/architect-vocabulary/SKILL.md +24 -21
- metadata +127 -68
- data/lib/space_architect/cli/config.rb +0 -61
- data/lib/space_architect/cli/current.rb +0 -22
- data/lib/space_architect/cli/helpers.rb +0 -117
- data/lib/space_architect/cli/init.rb +0 -35
- data/lib/space_architect/cli/list.rb +0 -30
- data/lib/space_architect/cli/new.rb +0 -43
- data/lib/space_architect/cli/options.rb +0 -12
- data/lib/space_architect/cli/path.rb +0 -22
- data/lib/space_architect/cli/repo.rb +0 -88
- data/lib/space_architect/cli/shell.rb +0 -137
- data/lib/space_architect/cli/show.rb +0 -27
- data/lib/space_architect/cli/status.rb +0 -39
- data/lib/space_architect/cli/use.rb +0 -23
- data/lib/space_architect/version.rb +0 -5
- data/vendor/repo-tender/lib/space_architect/pristine.rb +0 -44
|
@@ -1,32 +1,60 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Space::Architect
|
|
4
6
|
module CLI
|
|
5
7
|
module Architect
|
|
6
|
-
class Init <
|
|
7
|
-
|
|
8
|
-
include Helpers
|
|
9
|
-
|
|
10
|
-
desc "Scaffold architect mission memory in the current space"
|
|
8
|
+
class Init < BaseCommand
|
|
9
|
+
desc "Scaffold (or top up) the architect project: ARCHITECT.md, space.yaml project block, SessionStart hook"
|
|
11
10
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
12
11
|
|
|
13
12
|
def call(space: nil, **opts)
|
|
14
13
|
setup_terminal(**opts.slice(:color, :colors))
|
|
15
14
|
handle_errors do
|
|
16
15
|
render(store.find(space)) do |sp|
|
|
17
|
-
|
|
18
|
-
path =
|
|
19
|
-
terminal.say "
|
|
16
|
+
project = ArchitectProject.new(space: sp)
|
|
17
|
+
path = project.init!
|
|
18
|
+
terminal.say "Project ready: #{terminal.path(path)}"
|
|
20
19
|
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
21
20
|
end
|
|
22
21
|
end
|
|
23
22
|
end
|
|
24
23
|
end
|
|
25
24
|
|
|
26
|
-
class
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
class Ground < BaseCommand
|
|
26
|
+
desc "Print grounding reads (ARCHITECT.md, BRIEF.md, in-flight iteration) to stdout"
|
|
27
|
+
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
28
|
+
|
|
29
|
+
def call(space: nil, **opts)
|
|
30
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
31
|
+
handle_errors do
|
|
32
|
+
session_cwd = parse_session_cwd_from_stdin
|
|
33
|
+
render(store.find(space)) do |sp|
|
|
34
|
+
project = ArchitectProject.new(space: sp)
|
|
35
|
+
content = project.ground(session_cwd: session_cwd)
|
|
36
|
+
terminal.say content unless content.empty?
|
|
37
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# Read the session's working directory from the Claude Code hook JSON on stdin,
|
|
45
|
+
# falling back to Dir.pwd when stdin is a tty or returns nothing (e.g. direct
|
|
46
|
+
# terminal invocation, CI with /dev/null stdin, or in-process test invocation).
|
|
47
|
+
def parse_session_cwd_from_stdin
|
|
48
|
+
return Dir.pwd if $stdin.tty?
|
|
49
|
+
line = $stdin.gets
|
|
50
|
+
return Dir.pwd unless line
|
|
51
|
+
JSON.parse(line.strip)["cwd"] || Dir.pwd
|
|
52
|
+
rescue JSON::ParserError, TypeError
|
|
53
|
+
Dir.pwd
|
|
54
|
+
end
|
|
55
|
+
end
|
|
29
56
|
|
|
57
|
+
class New < BaseCommand
|
|
30
58
|
desc "Scaffold the next iteration file (architecture/I<NN>-<iteration>.md)"
|
|
31
59
|
argument :iteration, required: true, desc: "Iteration name (kebab-case)"
|
|
32
60
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -35,8 +63,8 @@ module SpaceArchitect
|
|
|
35
63
|
setup_terminal(**opts.slice(:color, :colors))
|
|
36
64
|
handle_errors do
|
|
37
65
|
render(store.find(space)) do |sp|
|
|
38
|
-
|
|
39
|
-
path =
|
|
66
|
+
project = ArchitectProject.new(space: sp)
|
|
67
|
+
path = project.new_iteration!(iteration)
|
|
40
68
|
terminal.say "Iteration scaffolded: #{terminal.path(path)}"
|
|
41
69
|
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
42
70
|
end
|
|
@@ -44,22 +72,19 @@ module SpaceArchitect
|
|
|
44
72
|
end
|
|
45
73
|
end
|
|
46
74
|
|
|
47
|
-
class Status <
|
|
48
|
-
|
|
49
|
-
include Helpers
|
|
50
|
-
|
|
51
|
-
desc "Show architect mission state (read-only)"
|
|
75
|
+
class Status < BaseCommand
|
|
76
|
+
desc "Show architect project state (read-only)"
|
|
52
77
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
53
78
|
|
|
54
79
|
def call(space: nil, **opts)
|
|
55
80
|
setup_terminal(**opts.slice(:color, :colors))
|
|
56
81
|
handle_errors do
|
|
57
82
|
render(store.find(space)) do |sp|
|
|
58
|
-
|
|
59
|
-
info =
|
|
83
|
+
project = ArchitectProject.new(space: sp)
|
|
84
|
+
info = project.status
|
|
60
85
|
block = info[:block]
|
|
61
86
|
|
|
62
|
-
terminal.say "
|
|
87
|
+
terminal.say "Project status: #{block['status'] || '(none)'}"
|
|
63
88
|
terminal.say "Current iteration: #{block['current_iteration'] || '(none)'}"
|
|
64
89
|
|
|
65
90
|
iterations = block["iterations"] || []
|
|
@@ -77,7 +102,14 @@ module SpaceArchitect
|
|
|
77
102
|
end.join(", ")
|
|
78
103
|
lanes = lane_list.any? { |l| l["variant"] } ? "variant: #{lanes_str}" : lanes_str
|
|
79
104
|
lanes = "#{lanes} → winner: #{s['winner']}" if s["winner"]
|
|
80
|
-
|
|
105
|
+
verdict_str = if s["verdict"] && s["verdict"] != "pending"
|
|
106
|
+
s["verdict"]
|
|
107
|
+
elsif (s["lanes"] || []).any? { |l| l["integration_branch"] }
|
|
108
|
+
"awaiting-verdict"
|
|
109
|
+
else
|
|
110
|
+
s["verdict"] || "-"
|
|
111
|
+
end
|
|
112
|
+
[nn, s["name"], s["freeze_sha"]&.[](0, 8) || "-", lanes, verdict_str]
|
|
81
113
|
end
|
|
82
114
|
terminal.say terminal.table(%w[II Iteration FreezeSHA Lanes Verdict], rows)
|
|
83
115
|
end
|
|
@@ -92,11 +124,8 @@ module SpaceArchitect
|
|
|
92
124
|
end
|
|
93
125
|
end
|
|
94
126
|
|
|
95
|
-
class Freeze <
|
|
96
|
-
|
|
97
|
-
include Helpers
|
|
98
|
-
|
|
99
|
-
desc "Freeze gates for an iteration"
|
|
127
|
+
class Freeze < BaseCommand
|
|
128
|
+
desc "Freeze the iteration's frozen region (Grounds/Specification/Acceptance Criteria) and record the freeze SHA"
|
|
100
129
|
argument :iteration, required: true, desc: "Iteration name"
|
|
101
130
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
102
131
|
|
|
@@ -104,10 +133,12 @@ module SpaceArchitect
|
|
|
104
133
|
setup_terminal(**opts.slice(:color, :colors))
|
|
105
134
|
handle_errors do
|
|
106
135
|
render(store.find(space)) do |sp|
|
|
107
|
-
|
|
108
|
-
|
|
136
|
+
project = ArchitectProject.new(space: sp)
|
|
137
|
+
warnings = []
|
|
138
|
+
sha = project.freeze!(iteration, warnings: warnings)
|
|
109
139
|
terminal.say "Frozen #{iteration} at #{sha}"
|
|
110
|
-
|
|
140
|
+
warnings.each { |w| terminal.say "Warning: #{w}" }
|
|
141
|
+
ac = project.acceptance_criteria(iteration)
|
|
111
142
|
unless ac.to_s.strip.empty?
|
|
112
143
|
terminal.say ""
|
|
113
144
|
terminal.say "Frozen Acceptance Criteria (quote these verbatim when judging):"
|
|
@@ -119,11 +150,8 @@ module SpaceArchitect
|
|
|
119
150
|
end
|
|
120
151
|
end
|
|
121
152
|
|
|
122
|
-
class Verify <
|
|
123
|
-
|
|
124
|
-
include Helpers
|
|
125
|
-
|
|
126
|
-
desc "Post-flight mechanical checks for an iteration (reports only, no judgment)"
|
|
153
|
+
class Verify < BaseCommand
|
|
154
|
+
desc "Post-flight mechanical lane checks — frozen-untouched, no builder commits, report exists, in-bounds (reports only, no judgment)"
|
|
127
155
|
argument :iteration, required: true, desc: "Iteration name"
|
|
128
156
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
129
157
|
|
|
@@ -131,8 +159,8 @@ module SpaceArchitect
|
|
|
131
159
|
setup_terminal(**opts.slice(:color, :colors))
|
|
132
160
|
handle_errors do
|
|
133
161
|
render(store.find(space)) do |sp|
|
|
134
|
-
|
|
135
|
-
results =
|
|
162
|
+
project = ArchitectProject.new(space: sp)
|
|
163
|
+
results = project.verify(iteration)
|
|
136
164
|
|
|
137
165
|
if results.empty?
|
|
138
166
|
terminal.say "No lanes recorded for iteration '#{iteration}'"
|
|
@@ -161,50 +189,69 @@ module SpaceArchitect
|
|
|
161
189
|
|
|
162
190
|
def pass_fail(val)
|
|
163
191
|
case val
|
|
164
|
-
when true
|
|
165
|
-
when false
|
|
166
|
-
|
|
192
|
+
when true then "PASS"
|
|
193
|
+
when false then "FAIL"
|
|
194
|
+
when :no_touch_set then "WARN — no touch_set recorded"
|
|
195
|
+
else "N/A"
|
|
167
196
|
end
|
|
168
197
|
end
|
|
169
198
|
end
|
|
170
199
|
|
|
171
|
-
class Dispatch <
|
|
172
|
-
include GlobalOptions
|
|
173
|
-
include Helpers
|
|
174
|
-
|
|
200
|
+
class Dispatch < BaseCommand
|
|
175
201
|
desc "Dispatch a builder for a lane (streams to build/<id>-<lane>/run.jsonl)"
|
|
176
202
|
argument :iteration, required: true, desc: "Iteration name"
|
|
177
203
|
argument :lane, required: true, desc: "Lane name"
|
|
178
204
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
179
|
-
option :model, default: nil,
|
|
180
|
-
option :max_turns, default: "200",
|
|
181
|
-
option :harness, default: nil,
|
|
182
|
-
option :effort, default: nil,
|
|
205
|
+
option :model, default: nil, desc: "Builder model to pin (default: the lane's model, else the reference default claude-sonnet-4-6). Any provider/tier; pin a full id, not a floating alias"
|
|
206
|
+
option :max_turns, default: "200", desc: "Max turns for the builder"
|
|
207
|
+
option :harness, default: nil, desc: "Harness override (claude-code, opencode)"
|
|
208
|
+
option :effort, default: nil, desc: "Reasoning effort override (opencode only; sets reasoningEffort in the model config)"
|
|
209
|
+
option :detach, type: :boolean, default: false, desc: "Detach the builder process (returns immediately with PID; poll report for completion)"
|
|
210
|
+
option :timeout, default: "14400", desc: "Wall-clock timeout in seconds (0 disables; default 4h); foreground only"
|
|
211
|
+
option :push_url, default: nil, desc: "HTTP endpoint for streaming push (POST body to this URL)"
|
|
212
|
+
option :push_token, default: nil, desc: "Bearer token for push endpoint authorization"
|
|
213
|
+
option :push_host, default: nil, desc: "Base URL of the ingest server; the CLI creates a run via POST <host>/runs and streams to /runs/<id>/ingest (requires --push-token)"
|
|
183
214
|
|
|
184
215
|
def call(iteration:, lane:, space: nil, model: nil,
|
|
185
|
-
max_turns: "200", harness: nil, effort: nil,
|
|
216
|
+
max_turns: "200", harness: nil, effort: nil, detach: false,
|
|
217
|
+
timeout: "14400", push_url: nil, push_token: nil, push_host: nil, **opts)
|
|
186
218
|
setup_terminal(**opts.slice(:color, :colors))
|
|
187
219
|
handle_errors do
|
|
188
220
|
render(store.find(space)) do |sp|
|
|
189
|
-
|
|
190
|
-
kwargs = { max_turns: max_turns.to_i }
|
|
191
|
-
kwargs[:model]
|
|
192
|
-
kwargs[:harness]
|
|
193
|
-
kwargs[:effort]
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
221
|
+
project = ArchitectProject.new(space: sp)
|
|
222
|
+
kwargs = { max_turns: max_turns.to_i, detach: detach }
|
|
223
|
+
kwargs[:model] = model if model
|
|
224
|
+
kwargs[:harness] = harness if harness
|
|
225
|
+
kwargs[:effort] = effort if effort
|
|
226
|
+
kwargs[:timeout] = timeout.to_i unless detach
|
|
227
|
+
kwargs[:push_url] = push_url if push_url
|
|
228
|
+
kwargs[:push_token] = push_token if push_token
|
|
229
|
+
kwargs[:push_host] = push_host if push_host
|
|
230
|
+
res = project.dispatch(iteration, lane, **kwargs)
|
|
231
|
+
if detach
|
|
232
|
+
terminal.say "PID: #{res[:pid]}"
|
|
233
|
+
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
234
|
+
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
235
|
+
terminal.say "Dispatched detached — poll #{terminal.path(res[:report])} for completion"
|
|
236
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
237
|
+
elsif res[:timed_out]
|
|
238
|
+
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
239
|
+
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
240
|
+
terminal.say "Builder TIMED OUT after #{timeout}s — process group killed. Re-dispatch (lanes are cheap)."
|
|
241
|
+
CLI.record_outcome(Outcome.new(exit_code: res[:exit_code]))
|
|
242
|
+
else
|
|
243
|
+
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
244
|
+
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
245
|
+
terminal.say "Ingest URL: #{res[:push_url]}" if res[:push_url]
|
|
246
|
+
terminal.say "Builder exited with status #{res[:exit_code]}"
|
|
247
|
+
CLI.record_outcome(Outcome.new(exit_code: res[:exit_code]))
|
|
248
|
+
end
|
|
199
249
|
end
|
|
200
250
|
end
|
|
201
251
|
end
|
|
202
252
|
end
|
|
203
253
|
|
|
204
|
-
class Section <
|
|
205
|
-
include GlobalOptions
|
|
206
|
-
include Helpers
|
|
207
|
-
|
|
254
|
+
class Section < BaseCommand
|
|
208
255
|
desc "Write a section of the iteration file and commit it (one call)"
|
|
209
256
|
argument :iteration, required: true, desc: "Iteration name"
|
|
210
257
|
argument :section, required: true, desc: "Section: grounds, specification, prompt, verdict"
|
|
@@ -220,8 +267,8 @@ module SpaceArchitect
|
|
|
220
267
|
handle_errors do
|
|
221
268
|
content = read_section_body(from: from, body: body, stdin: stdin)
|
|
222
269
|
render(store.find(space)) do |sp|
|
|
223
|
-
|
|
224
|
-
res =
|
|
270
|
+
project = ArchitectProject.new(space: sp)
|
|
271
|
+
res = project.write_section!(iteration, section, body: content, append: append, lane: lane)
|
|
225
272
|
if res[:committed]
|
|
226
273
|
terminal.say "Committed #{res[:heading]} → #{res[:sha][0, 8]}"
|
|
227
274
|
terminal.say res[:diffstat] unless res[:diffstat].empty?
|
|
@@ -239,14 +286,43 @@ module SpaceArchitect
|
|
|
239
286
|
return File.read(from) if from
|
|
240
287
|
return body if body
|
|
241
288
|
return $stdin.read if stdin
|
|
242
|
-
raise
|
|
289
|
+
raise Space::Core::Error, "provide the section body via --from <file>, --body <text>, or --stdin"
|
|
243
290
|
end
|
|
244
291
|
end
|
|
245
292
|
|
|
246
|
-
class
|
|
247
|
-
|
|
248
|
-
|
|
293
|
+
class Verdict < BaseCommand
|
|
294
|
+
desc "Record the architect's verdict decision (continue or kill) and write ## Verdict prose"
|
|
295
|
+
argument :iteration, required: true, desc: "Iteration name"
|
|
296
|
+
argument :decision, required: true, desc: "Decision: continue or kill"
|
|
297
|
+
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
298
|
+
option :from, default: nil, desc: "Read the verdict body from this file"
|
|
299
|
+
option :body, default: nil, desc: "Inline verdict body"
|
|
300
|
+
option :stdin, type: :boolean, default: false, desc: "Read the verdict body from stdin"
|
|
249
301
|
|
|
302
|
+
def call(iteration:, decision:, space: nil, from: nil, body: nil, stdin: false, **opts)
|
|
303
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
304
|
+
handle_errors do
|
|
305
|
+
content = read_section_body(from: from, body: body, stdin: stdin)
|
|
306
|
+
render(store.find(space)) do |sp|
|
|
307
|
+
project = ArchitectProject.new(space: sp)
|
|
308
|
+
res = project.record_verdict!(iteration, decision: decision, body: content)
|
|
309
|
+
terminal.say "Verdict '#{res[:decision]}' recorded → #{res[:sha][0, 8]}"
|
|
310
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
private
|
|
316
|
+
|
|
317
|
+
def read_section_body(from:, body:, stdin:)
|
|
318
|
+
return File.read(from) if from
|
|
319
|
+
return body if body
|
|
320
|
+
return $stdin.read if stdin
|
|
321
|
+
raise Space::Core::Error, "provide the verdict body via --from <file>, --body <text>, or --stdin"
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
class Evidence < BaseCommand
|
|
250
326
|
desc "Transcribe a lane's scratch report VERBATIM into Builder Report and commit"
|
|
251
327
|
argument :iteration, required: true, desc: "Iteration name"
|
|
252
328
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -256,8 +332,8 @@ module SpaceArchitect
|
|
|
256
332
|
setup_terminal(**opts.slice(:color, :colors))
|
|
257
333
|
handle_errors do
|
|
258
334
|
render(store.find(space)) do |sp|
|
|
259
|
-
|
|
260
|
-
res =
|
|
335
|
+
project = ArchitectProject.new(space: sp)
|
|
336
|
+
res = project.transcribe_evidence!(iteration, lane: lane)
|
|
261
337
|
terminal.say "Transcribed #{res[:lines]} lines → #{res[:sha][0, 8]}"
|
|
262
338
|
terminal.say "Builder STATUS: #{res[:status_line]}" if res[:status_line]
|
|
263
339
|
terminal.say "Now rule on the builder's PHASE 0 disagreements in the Verdict (a later session)."
|
|
@@ -267,10 +343,7 @@ module SpaceArchitect
|
|
|
267
343
|
end
|
|
268
344
|
end
|
|
269
345
|
|
|
270
|
-
class Merge <
|
|
271
|
-
include GlobalOptions
|
|
272
|
-
include Helpers
|
|
273
|
-
|
|
346
|
+
class Merge < BaseCommand
|
|
274
347
|
desc "Integrate ONE judged-passing lane (merges --no-ff; runs no gates, makes no verdict)"
|
|
275
348
|
argument :iteration, required: true, desc: "Iteration name"
|
|
276
349
|
argument :lane, required: true, desc: "Lane name (architect-judged passing)"
|
|
@@ -281,8 +354,8 @@ module SpaceArchitect
|
|
|
281
354
|
setup_terminal(**opts.slice(:color, :colors))
|
|
282
355
|
handle_errors do
|
|
283
356
|
render(store.find(space)) do |sp|
|
|
284
|
-
|
|
285
|
-
r =
|
|
357
|
+
project = ArchitectProject.new(space: sp)
|
|
358
|
+
r = project.merge_lane!(iteration, lane, message: message)
|
|
286
359
|
terminal.say "Merged #{lane} → #{r[:integration_branch]} (#{r[:merge_sha][0, 8]})"
|
|
287
360
|
terminal.say r[:diffstat] unless r[:diffstat].empty?
|
|
288
361
|
terminal.say "Gates NOT run — run `architect gate #{iteration}` against the integration branch."
|
|
@@ -292,10 +365,7 @@ module SpaceArchitect
|
|
|
292
365
|
end
|
|
293
366
|
end
|
|
294
367
|
|
|
295
|
-
class Integrate <
|
|
296
|
-
include GlobalOptions
|
|
297
|
-
include Helpers
|
|
298
|
-
|
|
368
|
+
class Integrate < BaseCommand
|
|
299
369
|
desc "Integrate the architect-supplied set of passing lanes, in order (stops on conflict)"
|
|
300
370
|
argument :iteration, required: true, desc: "Iteration name"
|
|
301
371
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -306,9 +376,9 @@ module SpaceArchitect
|
|
|
306
376
|
setup_terminal(**opts.slice(:color, :colors))
|
|
307
377
|
handle_errors do
|
|
308
378
|
render(store.find(space)) do |sp|
|
|
309
|
-
|
|
379
|
+
project = ArchitectProject.new(space: sp)
|
|
310
380
|
lane_names = lanes.to_s.split(",").map(&:strip).reject(&:empty?)
|
|
311
|
-
results =
|
|
381
|
+
results = project.integrate!(iteration, lanes: lane_names, teardown: teardown)
|
|
312
382
|
results.each do |r|
|
|
313
383
|
terminal.say "Merged #{r[:lane]} → #{r[:integration_branch]} (#{r[:merge_sha][0, 8]})"
|
|
314
384
|
end
|
|
@@ -319,11 +389,29 @@ module SpaceArchitect
|
|
|
319
389
|
end
|
|
320
390
|
end
|
|
321
391
|
|
|
322
|
-
class
|
|
323
|
-
|
|
324
|
-
|
|
392
|
+
class Land < BaseCommand
|
|
393
|
+
desc "Generate the end-of-project PR command (no push, no gh — prints gh pr create)"
|
|
394
|
+
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
325
395
|
|
|
326
|
-
|
|
396
|
+
def call(space: nil, **opts)
|
|
397
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
398
|
+
handle_errors do
|
|
399
|
+
render(store.find(space)) do |sp|
|
|
400
|
+
project = ArchitectProject.new(space: sp)
|
|
401
|
+
results = project.land
|
|
402
|
+
results.each do |r|
|
|
403
|
+
terminal.say r[:context]
|
|
404
|
+
terminal.say r[:command]
|
|
405
|
+
terminal.say "Body: #{terminal.path(r[:body_file])}"
|
|
406
|
+
end
|
|
407
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
class Gate < BaseCommand
|
|
414
|
+
desc "Run the frozen Acceptance Criteria gate commands and report PASS/FAIL"
|
|
327
415
|
argument :iteration, required: true, desc: "Iteration name"
|
|
328
416
|
argument :lane, required: false, desc: "Run in a lane worktree (default: the integration repo)"
|
|
329
417
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -332,26 +420,26 @@ module SpaceArchitect
|
|
|
332
420
|
setup_terminal(**opts.slice(:color, :colors))
|
|
333
421
|
handle_errors do
|
|
334
422
|
render(store.find(space)) do |sp|
|
|
335
|
-
|
|
336
|
-
results =
|
|
423
|
+
project = ArchitectProject.new(space: sp)
|
|
424
|
+
results = project.run_gates(iteration, lane: lane)
|
|
337
425
|
results.each do |r|
|
|
426
|
+
marker = r[:status] == :pass ? "PASS" : "FAIL"
|
|
338
427
|
terminal.say ""
|
|
339
|
-
terminal.say "── #{r[:ac].empty? ? "(gate)" : r[:ac]}: #{r[:
|
|
428
|
+
terminal.say "── #{r[:ac].empty? ? "(gate)" : r[:ac]}: #{r[:cmd]} (exit #{r[:exit_code]}) [#{marker}]"
|
|
429
|
+
terminal.say " reason: #{r[:reason]}" if r[:status] == :fail && !r[:reason].to_s.empty?
|
|
340
430
|
terminal.say r[:stdout].rstrip unless r[:stdout].strip.empty?
|
|
341
431
|
terminal.say r[:stderr].rstrip unless r[:stderr].strip.empty?
|
|
342
432
|
end
|
|
343
433
|
terminal.say ""
|
|
344
|
-
terminal.say "
|
|
345
|
-
|
|
434
|
+
terminal.say "Mechanical gate results above; the Acceptance-Criteria verdict — necessary, not sufficient — remains the architect's."
|
|
435
|
+
any_fail = results.any? { |r| r[:status] == :fail }
|
|
436
|
+
CLI.record_outcome(Outcome.new(exit_code: any_fail ? 1 : 0))
|
|
346
437
|
end
|
|
347
438
|
end
|
|
348
439
|
end
|
|
349
440
|
end
|
|
350
441
|
|
|
351
|
-
class InstallSkills <
|
|
352
|
-
include GlobalOptions
|
|
353
|
-
include Helpers
|
|
354
|
-
|
|
442
|
+
class InstallSkills < BaseCommand
|
|
355
443
|
desc "Install bundled skills (architect, architect-research, architect-vocabulary) for a harness"
|
|
356
444
|
option :provider, default: "claude", desc: "Harness: claude, codex, opencode, pi"
|
|
357
445
|
option :project, type: :boolean, default: false, desc: "Install to CWD instead of global"
|
|
@@ -373,34 +461,8 @@ module SpaceArchitect
|
|
|
373
461
|
end
|
|
374
462
|
end
|
|
375
463
|
|
|
376
|
-
module Brief
|
|
377
|
-
class New < Dry::CLI::Command
|
|
378
|
-
include GlobalOptions
|
|
379
|
-
include Helpers
|
|
380
|
-
|
|
381
|
-
desc "Scaffold the durable mission brief (architecture/BRIEF.md)"
|
|
382
|
-
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
383
|
-
option :force, type: :boolean, default: false, desc: "Overwrite an existing BRIEF.md"
|
|
384
|
-
|
|
385
|
-
def call(space: nil, force: false, **opts)
|
|
386
|
-
setup_terminal(**opts.slice(:color, :colors))
|
|
387
|
-
handle_errors do
|
|
388
|
-
render(store.find(space)) do |sp|
|
|
389
|
-
mission = ArchitectMission.new(space: sp)
|
|
390
|
-
path = mission.brief_new!(force: force)
|
|
391
|
-
terminal.say "Brief ready: #{terminal.path(path)}"
|
|
392
|
-
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
393
|
-
end
|
|
394
|
-
end
|
|
395
|
-
end
|
|
396
|
-
end
|
|
397
|
-
end
|
|
398
|
-
|
|
399
464
|
module Worktree
|
|
400
|
-
class Add <
|
|
401
|
-
include GlobalOptions
|
|
402
|
-
include Helpers
|
|
403
|
-
|
|
465
|
+
class Add < BaseCommand
|
|
404
466
|
desc "Create a worktree for a lane"
|
|
405
467
|
argument :repo, required: true, desc: "Repo name (under repos/)"
|
|
406
468
|
argument :iteration, required: true, desc: "Iteration name"
|
|
@@ -415,9 +477,9 @@ module SpaceArchitect
|
|
|
415
477
|
setup_terminal(**opts.slice(:color, :colors))
|
|
416
478
|
handle_errors do
|
|
417
479
|
render(store.find) do |sp|
|
|
418
|
-
|
|
480
|
+
project = ArchitectProject.new(space: sp)
|
|
419
481
|
touch_set = touch ? touch.split(",").map(&:strip).reject(&:empty?) : nil
|
|
420
|
-
result =
|
|
482
|
+
result = project.worktree_add(repo, iteration, lane, base: base,
|
|
421
483
|
harness: harness, model: model, effort: effort, touch: touch_set)
|
|
422
484
|
terminal.say "Worktree: #{terminal.path(result[:worktree])}"
|
|
423
485
|
terminal.say "Base SHA: #{result[:base_sha]}"
|
|
@@ -427,10 +489,7 @@ module SpaceArchitect
|
|
|
427
489
|
end
|
|
428
490
|
end
|
|
429
491
|
|
|
430
|
-
class Remove <
|
|
431
|
-
include GlobalOptions
|
|
432
|
-
include Helpers
|
|
433
|
-
|
|
492
|
+
class Remove < BaseCommand
|
|
434
493
|
desc "Remove a lane worktree"
|
|
435
494
|
argument :iteration, required: true, desc: "Iteration name"
|
|
436
495
|
argument :lane, required: true, desc: "Lane name"
|
|
@@ -439,8 +498,8 @@ module SpaceArchitect
|
|
|
439
498
|
setup_terminal(**opts.slice(:color, :colors))
|
|
440
499
|
handle_errors do
|
|
441
500
|
render(store.find) do |sp|
|
|
442
|
-
|
|
443
|
-
|
|
501
|
+
project = ArchitectProject.new(space: sp)
|
|
502
|
+
project.worktree_remove(iteration, lane)
|
|
444
503
|
terminal.say "Removed worktree for #{iteration}/#{lane}"
|
|
445
504
|
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
446
505
|
end
|
|
@@ -448,18 +507,15 @@ module SpaceArchitect
|
|
|
448
507
|
end
|
|
449
508
|
end
|
|
450
509
|
|
|
451
|
-
class List <
|
|
452
|
-
include GlobalOptions
|
|
453
|
-
include Helpers
|
|
454
|
-
|
|
510
|
+
class List < BaseCommand
|
|
455
511
|
desc "List active architect worktrees"
|
|
456
512
|
|
|
457
513
|
def call(**opts)
|
|
458
514
|
setup_terminal(**opts.slice(:color, :colors))
|
|
459
515
|
handle_errors do
|
|
460
516
|
render(store.find) do |sp|
|
|
461
|
-
|
|
462
|
-
worktrees =
|
|
517
|
+
project = ArchitectProject.new(space: sp)
|
|
518
|
+
worktrees = project.worktree_list
|
|
463
519
|
if worktrees.empty?
|
|
464
520
|
terminal.say "No active architect worktrees"
|
|
465
521
|
else
|
|
@@ -473,10 +529,7 @@ module SpaceArchitect
|
|
|
473
529
|
end
|
|
474
530
|
|
|
475
531
|
module Variant
|
|
476
|
-
class Add <
|
|
477
|
-
include GlobalOptions
|
|
478
|
-
include Helpers
|
|
479
|
-
|
|
532
|
+
class Add < BaseCommand
|
|
480
533
|
desc "Create a variant set (competing lanes over one frozen spec)"
|
|
481
534
|
argument :repo, required: true, desc: "Repo name (under repos/)"
|
|
482
535
|
argument :iteration, required: true, desc: "Iteration name"
|
|
@@ -495,8 +548,8 @@ module SpaceArchitect
|
|
|
495
548
|
[harness, model]
|
|
496
549
|
end
|
|
497
550
|
|
|
498
|
-
|
|
499
|
-
variants =
|
|
551
|
+
project = ArchitectProject.new(space: sp)
|
|
552
|
+
variants = project.variant_add(repo, iteration, parsed_pairs, base: base, prompt: prompt)
|
|
500
553
|
variants.each do |v|
|
|
501
554
|
terminal.say "#{v[:name]} · #{v[:harness]} · #{v[:model] || "(default)"} · #{terminal.path(v[:worktree])}"
|
|
502
555
|
end
|
|
@@ -506,10 +559,7 @@ module SpaceArchitect
|
|
|
506
559
|
end
|
|
507
560
|
end
|
|
508
561
|
|
|
509
|
-
class Promote <
|
|
510
|
-
include GlobalOptions
|
|
511
|
-
include Helpers
|
|
512
|
-
|
|
562
|
+
class Promote < BaseCommand
|
|
513
563
|
desc "Promote one variant of a variant set as the winner"
|
|
514
564
|
argument :iteration, required: true, desc: "Iteration name"
|
|
515
565
|
argument :winner, required: true, desc: "Variant lane name to promote (e.g. v02)"
|
|
@@ -519,8 +569,8 @@ module SpaceArchitect
|
|
|
519
569
|
setup_terminal(**opts.slice(:color, :colors))
|
|
520
570
|
handle_errors do
|
|
521
571
|
render(store.find(space)) do |sp|
|
|
522
|
-
|
|
523
|
-
result =
|
|
572
|
+
project = ArchitectProject.new(space: sp)
|
|
573
|
+
result = project.variant_promote(iteration, winner)
|
|
524
574
|
if result[:discarded].any?
|
|
525
575
|
terminal.say "Promoted #{result[:winner]} (discarded: #{result[:discarded].join(', ')})"
|
|
526
576
|
else
|
|
@@ -532,10 +582,7 @@ module SpaceArchitect
|
|
|
532
582
|
end
|
|
533
583
|
end
|
|
534
584
|
|
|
535
|
-
class Compare <
|
|
536
|
-
include GlobalOptions
|
|
537
|
-
include Helpers
|
|
538
|
-
|
|
585
|
+
class Compare < BaseCommand
|
|
539
586
|
desc "Compare variants of an iteration's variant set (read-only)"
|
|
540
587
|
argument :iteration, required: true, desc: "Iteration name"
|
|
541
588
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -544,8 +591,8 @@ module SpaceArchitect
|
|
|
544
591
|
setup_terminal(**opts.slice(:color, :colors))
|
|
545
592
|
handle_errors do
|
|
546
593
|
render(store.find(space)) do |sp|
|
|
547
|
-
|
|
548
|
-
info =
|
|
594
|
+
project = ArchitectProject.new(space: sp)
|
|
595
|
+
info = project.variant_compare(iteration)
|
|
549
596
|
|
|
550
597
|
terminal.say "Variant comparison: #{iteration} (freeze #{info[:freeze_sha]&.[](0, 8) || "-"})"
|
|
551
598
|
terminal.say "Winner: #{info[:winner] || '(none)'}"
|
|
@@ -569,32 +616,55 @@ module SpaceArchitect
|
|
|
569
616
|
end
|
|
570
617
|
end
|
|
571
618
|
end
|
|
619
|
+
|
|
620
|
+
module Brief
|
|
621
|
+
class New < BaseCommand
|
|
622
|
+
desc "Scaffold the durable project brief (architecture/BRIEF.md)"
|
|
623
|
+
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
624
|
+
option :force, type: :boolean, default: false, desc: "Overwrite an existing BRIEF.md"
|
|
625
|
+
|
|
626
|
+
def call(space: nil, force: false, **opts)
|
|
627
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
628
|
+
handle_errors do
|
|
629
|
+
render(store.find(space)) do |sp|
|
|
630
|
+
project = ArchitectProject.new(space: sp)
|
|
631
|
+
path = project.brief_new!(force: force)
|
|
632
|
+
terminal.say "Brief ready: #{terminal.path(path)}"
|
|
633
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
634
|
+
end
|
|
635
|
+
end
|
|
636
|
+
end
|
|
637
|
+
end
|
|
638
|
+
end
|
|
572
639
|
end
|
|
573
640
|
end
|
|
574
641
|
end
|
|
575
642
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
643
|
+
Space::Architect::CLI::Registry.register "init", Space::Architect::CLI::Architect::Init
|
|
644
|
+
Space::Architect::CLI::Registry.register "ground", Space::Architect::CLI::Architect::Ground
|
|
645
|
+
Space::Architect::CLI::Registry.register "new", Space::Architect::CLI::Architect::New
|
|
646
|
+
Space::Architect::CLI::Registry.register "status", Space::Architect::CLI::Architect::Status
|
|
647
|
+
Space::Architect::CLI::Registry.register "freeze", Space::Architect::CLI::Architect::Freeze
|
|
648
|
+
Space::Architect::CLI::Registry.register "verify", Space::Architect::CLI::Architect::Verify
|
|
649
|
+
Space::Architect::CLI::Registry.register "dispatch", Space::Architect::CLI::Architect::Dispatch
|
|
650
|
+
Space::Architect::CLI::Registry.register "section", Space::Architect::CLI::Architect::Section
|
|
651
|
+
Space::Architect::CLI::Registry.register "verdict", Space::Architect::CLI::Architect::Verdict
|
|
652
|
+
Space::Architect::CLI::Registry.register "evidence", Space::Architect::CLI::Architect::Evidence
|
|
653
|
+
Space::Architect::CLI::Registry.register "merge", Space::Architect::CLI::Architect::Merge
|
|
654
|
+
Space::Architect::CLI::Registry.register "integrate", Space::Architect::CLI::Architect::Integrate
|
|
655
|
+
Space::Architect::CLI::Registry.register "land", Space::Architect::CLI::Architect::Land
|
|
656
|
+
Space::Architect::CLI::Registry.register "gate", Space::Architect::CLI::Architect::Gate
|
|
657
|
+
Space::Architect::CLI::Registry.register "install-skills", Space::Architect::CLI::Architect::InstallSkills
|
|
658
|
+
Space::Architect::CLI::Registry.register "brief" do |b|
|
|
659
|
+
b.register "new", Space::Architect::CLI::Architect::Brief::New
|
|
590
660
|
end
|
|
591
|
-
|
|
592
|
-
wt.register "add",
|
|
593
|
-
wt.register "remove",
|
|
594
|
-
wt.register "list",
|
|
661
|
+
Space::Architect::CLI::Registry.register "worktree" do |wt|
|
|
662
|
+
wt.register "add", Space::Architect::CLI::Architect::Worktree::Add
|
|
663
|
+
wt.register "remove", Space::Architect::CLI::Architect::Worktree::Remove
|
|
664
|
+
wt.register "list", Space::Architect::CLI::Architect::Worktree::List
|
|
595
665
|
end
|
|
596
|
-
|
|
597
|
-
v.register "add",
|
|
598
|
-
v.register "promote",
|
|
599
|
-
v.register "compare",
|
|
666
|
+
Space::Architect::CLI::Registry.register "variant" do |v|
|
|
667
|
+
v.register "add", Space::Architect::CLI::Architect::Variant::Add
|
|
668
|
+
v.register "promote", Space::Architect::CLI::Architect::Variant::Promote
|
|
669
|
+
v.register "compare", Space::Architect::CLI::Architect::Variant::Compare
|
|
600
670
|
end
|