space-architect 1.2.0 → 2.0.0.rc1
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 +248 -146
- data/exe/architect +1 -1
- data/exe/space +2 -2
- data/exe/src +13 -0
- data/lib/space_architect/architect_mission.rb +84 -53
- data/lib/space_architect/cli/architect.rb +107 -121
- 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/harness.rb +123 -16
- 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 +109 -0
- data/lib/space_architect.rb +5 -19
- 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/config.rb +49 -0
- data/lib/space_core/cli/current.rb +16 -0
- data/lib/space_core/cli/help.rb +110 -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/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/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 +171 -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_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 +1 -1
- data/lib/{space_architect → space_core}/space_store.rb +12 -12
- data/lib/{space_architect → space_core}/state.rb +1 -1
- data/lib/{space_architect → space_core}/terminal.rb +16 -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 +40 -18
- 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 +329 -0
- data/skill/architect/dispatch.md +308 -0
- data/skill/architect/research.md +98 -0
- data/skill/architect-research/SKILL.md +165 -0
- data/skill/architect-research/lanes.md +191 -0
- data/skill/architect-vocabulary/SKILL.md +141 -0
- metadata +122 -67
- 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 -37
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
module
|
|
3
|
+
module Space::Architect
|
|
4
4
|
module CLI
|
|
5
5
|
module Architect
|
|
6
|
-
class Init <
|
|
7
|
-
include GlobalOptions
|
|
8
|
-
include Helpers
|
|
9
|
-
|
|
6
|
+
class Init < BaseCommand
|
|
10
7
|
desc "Scaffold architect mission memory in the current space"
|
|
11
8
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
12
9
|
|
|
@@ -23,10 +20,7 @@ module SpaceArchitect
|
|
|
23
20
|
end
|
|
24
21
|
end
|
|
25
22
|
|
|
26
|
-
class New <
|
|
27
|
-
include GlobalOptions
|
|
28
|
-
include Helpers
|
|
29
|
-
|
|
23
|
+
class New < BaseCommand
|
|
30
24
|
desc "Scaffold the next iteration file (architecture/I<NN>-<iteration>.md)"
|
|
31
25
|
argument :iteration, required: true, desc: "Iteration name (kebab-case)"
|
|
32
26
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -44,10 +38,7 @@ module SpaceArchitect
|
|
|
44
38
|
end
|
|
45
39
|
end
|
|
46
40
|
|
|
47
|
-
class Status <
|
|
48
|
-
include GlobalOptions
|
|
49
|
-
include Helpers
|
|
50
|
-
|
|
41
|
+
class Status < BaseCommand
|
|
51
42
|
desc "Show architect mission state (read-only)"
|
|
52
43
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
53
44
|
|
|
@@ -92,10 +83,7 @@ module SpaceArchitect
|
|
|
92
83
|
end
|
|
93
84
|
end
|
|
94
85
|
|
|
95
|
-
class Freeze <
|
|
96
|
-
include GlobalOptions
|
|
97
|
-
include Helpers
|
|
98
|
-
|
|
86
|
+
class Freeze < BaseCommand
|
|
99
87
|
desc "Freeze gates for an iteration"
|
|
100
88
|
argument :iteration, required: true, desc: "Iteration name"
|
|
101
89
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -119,10 +107,7 @@ module SpaceArchitect
|
|
|
119
107
|
end
|
|
120
108
|
end
|
|
121
109
|
|
|
122
|
-
class Verify <
|
|
123
|
-
include GlobalOptions
|
|
124
|
-
include Helpers
|
|
125
|
-
|
|
110
|
+
class Verify < BaseCommand
|
|
126
111
|
desc "Post-flight mechanical checks for an iteration (reports only, no judgment)"
|
|
127
112
|
argument :iteration, required: true, desc: "Iteration name"
|
|
128
113
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -168,43 +153,54 @@ module SpaceArchitect
|
|
|
168
153
|
end
|
|
169
154
|
end
|
|
170
155
|
|
|
171
|
-
class Dispatch <
|
|
172
|
-
include GlobalOptions
|
|
173
|
-
include Helpers
|
|
174
|
-
|
|
156
|
+
class Dispatch < BaseCommand
|
|
175
157
|
desc "Dispatch a builder for a lane (streams to build/<id>-<lane>/run.jsonl)"
|
|
176
158
|
argument :iteration, required: true, desc: "Iteration name"
|
|
177
159
|
argument :lane, required: true, desc: "Lane name"
|
|
178
160
|
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,
|
|
161
|
+
option :model, default: nil, desc: "Model to use (default: lane entry or claude-sonnet-4-6)"
|
|
162
|
+
option :max_turns, default: "200", desc: "Max turns for the builder"
|
|
163
|
+
option :harness, default: nil, desc: "Harness override (claude-code, opencode)"
|
|
164
|
+
option :effort, default: nil, desc: "Reasoning effort override (opencode only; sets reasoningEffort in the model config)"
|
|
165
|
+
option :detach, type: :boolean, default: false, desc: "Detach the builder process (returns immediately with PID; poll report for completion)"
|
|
166
|
+
option :push_url, default: nil, desc: "HTTP endpoint for streaming push (POST body to this URL)"
|
|
167
|
+
option :push_token, default: nil, desc: "Bearer token for push endpoint authorization"
|
|
168
|
+
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
169
|
|
|
184
170
|
def call(iteration:, lane:, space: nil, model: nil,
|
|
185
|
-
max_turns: "200", harness: nil, effort: nil,
|
|
171
|
+
max_turns: "200", harness: nil, effort: nil, detach: false,
|
|
172
|
+
push_url: nil, push_token: nil, push_host: nil, **opts)
|
|
186
173
|
setup_terminal(**opts.slice(:color, :colors))
|
|
187
174
|
handle_errors do
|
|
188
175
|
render(store.find(space)) do |sp|
|
|
189
176
|
mission = ArchitectMission.new(space: sp)
|
|
190
|
-
kwargs = { max_turns: max_turns.to_i }
|
|
191
|
-
kwargs[:model]
|
|
192
|
-
kwargs[:harness]
|
|
193
|
-
kwargs[:effort]
|
|
177
|
+
kwargs = { max_turns: max_turns.to_i, detach: detach }
|
|
178
|
+
kwargs[:model] = model if model
|
|
179
|
+
kwargs[:harness] = harness if harness
|
|
180
|
+
kwargs[:effort] = effort if effort
|
|
181
|
+
kwargs[:push_url] = push_url if push_url
|
|
182
|
+
kwargs[:push_token] = push_token if push_token
|
|
183
|
+
kwargs[:push_host] = push_host if push_host
|
|
194
184
|
res = mission.dispatch(iteration, lane, **kwargs)
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
185
|
+
if detach
|
|
186
|
+
terminal.say "PID: #{res[:pid]}"
|
|
187
|
+
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
188
|
+
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
189
|
+
terminal.say "Dispatched detached — poll #{terminal.path(res[:report])} for completion"
|
|
190
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
191
|
+
else
|
|
192
|
+
terminal.say "Run log: #{terminal.path(res[:run_log])}"
|
|
193
|
+
terminal.say "Report: #{terminal.path(res[:report])}"
|
|
194
|
+
terminal.say "Ingest URL: #{res[:push_url]}" if res[:push_url]
|
|
195
|
+
terminal.say "Builder exited with status #{res[:exit_code]}"
|
|
196
|
+
CLI.record_outcome(Outcome.new(exit_code: res[:exit_code]))
|
|
197
|
+
end
|
|
199
198
|
end
|
|
200
199
|
end
|
|
201
200
|
end
|
|
202
201
|
end
|
|
203
202
|
|
|
204
|
-
class Section <
|
|
205
|
-
include GlobalOptions
|
|
206
|
-
include Helpers
|
|
207
|
-
|
|
203
|
+
class Section < BaseCommand
|
|
208
204
|
desc "Write a section of the iteration file and commit it (one call)"
|
|
209
205
|
argument :iteration, required: true, desc: "Iteration name"
|
|
210
206
|
argument :section, required: true, desc: "Section: grounds, specification, prompt, verdict"
|
|
@@ -239,14 +235,11 @@ module SpaceArchitect
|
|
|
239
235
|
return File.read(from) if from
|
|
240
236
|
return body if body
|
|
241
237
|
return $stdin.read if stdin
|
|
242
|
-
raise
|
|
238
|
+
raise Space::Core::Error, "provide the section body via --from <file>, --body <text>, or --stdin"
|
|
243
239
|
end
|
|
244
240
|
end
|
|
245
241
|
|
|
246
|
-
class Evidence <
|
|
247
|
-
include GlobalOptions
|
|
248
|
-
include Helpers
|
|
249
|
-
|
|
242
|
+
class Evidence < BaseCommand
|
|
250
243
|
desc "Transcribe a lane's scratch report VERBATIM into Builder Report and commit"
|
|
251
244
|
argument :iteration, required: true, desc: "Iteration name"
|
|
252
245
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -267,10 +260,7 @@ module SpaceArchitect
|
|
|
267
260
|
end
|
|
268
261
|
end
|
|
269
262
|
|
|
270
|
-
class Merge <
|
|
271
|
-
include GlobalOptions
|
|
272
|
-
include Helpers
|
|
273
|
-
|
|
263
|
+
class Merge < BaseCommand
|
|
274
264
|
desc "Integrate ONE judged-passing lane (merges --no-ff; runs no gates, makes no verdict)"
|
|
275
265
|
argument :iteration, required: true, desc: "Iteration name"
|
|
276
266
|
argument :lane, required: true, desc: "Lane name (architect-judged passing)"
|
|
@@ -292,10 +282,7 @@ module SpaceArchitect
|
|
|
292
282
|
end
|
|
293
283
|
end
|
|
294
284
|
|
|
295
|
-
class Integrate <
|
|
296
|
-
include GlobalOptions
|
|
297
|
-
include Helpers
|
|
298
|
-
|
|
285
|
+
class Integrate < BaseCommand
|
|
299
286
|
desc "Integrate the architect-supplied set of passing lanes, in order (stops on conflict)"
|
|
300
287
|
argument :iteration, required: true, desc: "Iteration name"
|
|
301
288
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -319,10 +306,7 @@ module SpaceArchitect
|
|
|
319
306
|
end
|
|
320
307
|
end
|
|
321
308
|
|
|
322
|
-
class Gate <
|
|
323
|
-
include GlobalOptions
|
|
324
|
-
include Helpers
|
|
325
|
-
|
|
309
|
+
class Gate < BaseCommand
|
|
326
310
|
desc "Run the frozen Acceptance Criteria gate commands and stream raw output (no PASS/FAIL)"
|
|
327
311
|
argument :iteration, required: true, desc: "Iteration name"
|
|
328
312
|
argument :lane, required: false, desc: "Run in a lane worktree (default: the integration repo)"
|
|
@@ -348,34 +332,30 @@ module SpaceArchitect
|
|
|
348
332
|
end
|
|
349
333
|
end
|
|
350
334
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
335
|
+
class InstallSkills < BaseCommand
|
|
336
|
+
desc "Install bundled skills (architect, architect-research, architect-vocabulary) for a harness"
|
|
337
|
+
option :provider, default: "claude", desc: "Harness: claude, codex, opencode, pi"
|
|
338
|
+
option :project, type: :boolean, default: false, desc: "Install to CWD instead of global"
|
|
339
|
+
option :force, type: :boolean, default: false, desc: "Overwrite existing skills that differ"
|
|
340
|
+
option :dry_run, type: :boolean, default: false, desc: "Print what would happen without writing files"
|
|
355
341
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
path = mission.brief_new!(force: force)
|
|
366
|
-
terminal.say "Brief ready: #{terminal.path(path)}"
|
|
367
|
-
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
368
|
-
end
|
|
342
|
+
def call(provider: "claude", project: false, force: false, dry_run: false, **opts)
|
|
343
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
344
|
+
handle_errors do
|
|
345
|
+
result = SkillInstaller.install(provider, project: project, force: force,
|
|
346
|
+
env: project_config.env, dry_run: dry_run)
|
|
347
|
+
verb = dry_run ? "Would install" : "Installed"
|
|
348
|
+
terminal.say "#{verb} skills for #{provider} → #{terminal.path(result[:dest_root])}"
|
|
349
|
+
result[:skills].each do |s|
|
|
350
|
+
terminal.say " #{s[:name]}: #{terminal.style_skill_action(s[:action])} (#{terminal.path(s[:path])})"
|
|
369
351
|
end
|
|
352
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
370
353
|
end
|
|
371
354
|
end
|
|
372
355
|
end
|
|
373
356
|
|
|
374
357
|
module Worktree
|
|
375
|
-
class Add <
|
|
376
|
-
include GlobalOptions
|
|
377
|
-
include Helpers
|
|
378
|
-
|
|
358
|
+
class Add < BaseCommand
|
|
379
359
|
desc "Create a worktree for a lane"
|
|
380
360
|
argument :repo, required: true, desc: "Repo name (under repos/)"
|
|
381
361
|
argument :iteration, required: true, desc: "Iteration name"
|
|
@@ -402,10 +382,7 @@ module SpaceArchitect
|
|
|
402
382
|
end
|
|
403
383
|
end
|
|
404
384
|
|
|
405
|
-
class Remove <
|
|
406
|
-
include GlobalOptions
|
|
407
|
-
include Helpers
|
|
408
|
-
|
|
385
|
+
class Remove < BaseCommand
|
|
409
386
|
desc "Remove a lane worktree"
|
|
410
387
|
argument :iteration, required: true, desc: "Iteration name"
|
|
411
388
|
argument :lane, required: true, desc: "Lane name"
|
|
@@ -423,10 +400,7 @@ module SpaceArchitect
|
|
|
423
400
|
end
|
|
424
401
|
end
|
|
425
402
|
|
|
426
|
-
class List <
|
|
427
|
-
include GlobalOptions
|
|
428
|
-
include Helpers
|
|
429
|
-
|
|
403
|
+
class List < BaseCommand
|
|
430
404
|
desc "List active architect worktrees"
|
|
431
405
|
|
|
432
406
|
def call(**opts)
|
|
@@ -448,10 +422,7 @@ module SpaceArchitect
|
|
|
448
422
|
end
|
|
449
423
|
|
|
450
424
|
module Variant
|
|
451
|
-
class Add <
|
|
452
|
-
include GlobalOptions
|
|
453
|
-
include Helpers
|
|
454
|
-
|
|
425
|
+
class Add < BaseCommand
|
|
455
426
|
desc "Create a variant set (competing lanes over one frozen spec)"
|
|
456
427
|
argument :repo, required: true, desc: "Repo name (under repos/)"
|
|
457
428
|
argument :iteration, required: true, desc: "Iteration name"
|
|
@@ -481,10 +452,7 @@ module SpaceArchitect
|
|
|
481
452
|
end
|
|
482
453
|
end
|
|
483
454
|
|
|
484
|
-
class Promote <
|
|
485
|
-
include GlobalOptions
|
|
486
|
-
include Helpers
|
|
487
|
-
|
|
455
|
+
class Promote < BaseCommand
|
|
488
456
|
desc "Promote one variant of a variant set as the winner"
|
|
489
457
|
argument :iteration, required: true, desc: "Iteration name"
|
|
490
458
|
argument :winner, required: true, desc: "Variant lane name to promote (e.g. v02)"
|
|
@@ -507,10 +475,7 @@ module SpaceArchitect
|
|
|
507
475
|
end
|
|
508
476
|
end
|
|
509
477
|
|
|
510
|
-
class Compare <
|
|
511
|
-
include GlobalOptions
|
|
512
|
-
include Helpers
|
|
513
|
-
|
|
478
|
+
class Compare < BaseCommand
|
|
514
479
|
desc "Compare variants of an iteration's variant set (read-only)"
|
|
515
480
|
argument :iteration, required: true, desc: "Iteration name"
|
|
516
481
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -544,31 +509,52 @@ module SpaceArchitect
|
|
|
544
509
|
end
|
|
545
510
|
end
|
|
546
511
|
end
|
|
512
|
+
|
|
513
|
+
module Brief
|
|
514
|
+
class New < BaseCommand
|
|
515
|
+
desc "Scaffold the durable mission brief (architecture/BRIEF.md)"
|
|
516
|
+
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
517
|
+
option :force, type: :boolean, default: false, desc: "Overwrite an existing BRIEF.md"
|
|
518
|
+
|
|
519
|
+
def call(space: nil, force: false, **opts)
|
|
520
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
521
|
+
handle_errors do
|
|
522
|
+
render(store.find(space)) do |sp|
|
|
523
|
+
mission = ArchitectMission.new(space: sp)
|
|
524
|
+
path = mission.brief_new!(force: force)
|
|
525
|
+
terminal.say "Brief ready: #{terminal.path(path)}"
|
|
526
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
end
|
|
547
532
|
end
|
|
548
533
|
end
|
|
549
534
|
end
|
|
550
535
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
536
|
+
Space::Architect::CLI::Registry.register "init", Space::Architect::CLI::Architect::Init
|
|
537
|
+
Space::Architect::CLI::Registry.register "new", Space::Architect::CLI::Architect::New
|
|
538
|
+
Space::Architect::CLI::Registry.register "status", Space::Architect::CLI::Architect::Status
|
|
539
|
+
Space::Architect::CLI::Registry.register "freeze", Space::Architect::CLI::Architect::Freeze
|
|
540
|
+
Space::Architect::CLI::Registry.register "verify", Space::Architect::CLI::Architect::Verify
|
|
541
|
+
Space::Architect::CLI::Registry.register "dispatch", Space::Architect::CLI::Architect::Dispatch
|
|
542
|
+
Space::Architect::CLI::Registry.register "section", Space::Architect::CLI::Architect::Section
|
|
543
|
+
Space::Architect::CLI::Registry.register "evidence", Space::Architect::CLI::Architect::Evidence
|
|
544
|
+
Space::Architect::CLI::Registry.register "merge", Space::Architect::CLI::Architect::Merge
|
|
545
|
+
Space::Architect::CLI::Registry.register "integrate", Space::Architect::CLI::Architect::Integrate
|
|
546
|
+
Space::Architect::CLI::Registry.register "gate", Space::Architect::CLI::Architect::Gate
|
|
547
|
+
Space::Architect::CLI::Registry.register "install-skills", Space::Architect::CLI::Architect::InstallSkills
|
|
548
|
+
Space::Architect::CLI::Registry.register "brief" do |b|
|
|
549
|
+
b.register "new", Space::Architect::CLI::Architect::Brief::New
|
|
564
550
|
end
|
|
565
|
-
|
|
566
|
-
wt.register "add",
|
|
567
|
-
wt.register "remove",
|
|
568
|
-
wt.register "list",
|
|
551
|
+
Space::Architect::CLI::Registry.register "worktree" do |wt|
|
|
552
|
+
wt.register "add", Space::Architect::CLI::Architect::Worktree::Add
|
|
553
|
+
wt.register "remove", Space::Architect::CLI::Architect::Worktree::Remove
|
|
554
|
+
wt.register "list", Space::Architect::CLI::Architect::Worktree::List
|
|
569
555
|
end
|
|
570
|
-
|
|
571
|
-
v.register "add",
|
|
572
|
-
v.register "promote",
|
|
573
|
-
v.register "compare",
|
|
556
|
+
Space::Architect::CLI::Registry.register "variant" do |v|
|
|
557
|
+
v.register "add", Space::Architect::CLI::Architect::Variant::Add
|
|
558
|
+
v.register "promote", Space::Architect::CLI::Architect::Variant::Promote
|
|
559
|
+
v.register "compare", Space::Architect::CLI::Architect::Variant::Compare
|
|
574
560
|
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Space::Architect
|
|
4
|
+
module CLI
|
|
5
|
+
module Architect
|
|
6
|
+
module Research
|
|
7
|
+
class Dispatch < BaseCommand
|
|
8
|
+
desc "Dispatch detached read-only research lanes (one per prompt file)"
|
|
9
|
+
argument :prompts, required: true,
|
|
10
|
+
desc: "Prompt file(s) to dispatch (space-separated paths)"
|
|
11
|
+
option :model, default: nil, desc: "Model override (default: claude-sonnet-4-6)"
|
|
12
|
+
option :max_turns, default: "40", desc: "Max turns per researcher"
|
|
13
|
+
|
|
14
|
+
def call(prompts:, model: nil, max_turns: "40", **opts)
|
|
15
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
16
|
+
handle_errors do
|
|
17
|
+
render(store.find(opts[:space])) do |sp|
|
|
18
|
+
paths = Array(prompts)
|
|
19
|
+
supervisor = Space::Architect::Research::Supervisor.new(space: sp)
|
|
20
|
+
kwargs = { max_turns: max_turns.to_i }
|
|
21
|
+
kwargs[:model] = model if model
|
|
22
|
+
runs = supervisor.dispatch(paths, **kwargs)
|
|
23
|
+
runs.each do |run|
|
|
24
|
+
terminal.say "dispatched #{run.id} (pid #{run.pid}) → #{terminal.path(run.run_log_path)}"
|
|
25
|
+
end
|
|
26
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class Status < BaseCommand
|
|
33
|
+
desc "Show status of dispatched research runs"
|
|
34
|
+
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
35
|
+
|
|
36
|
+
def call(space: nil, **opts)
|
|
37
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
38
|
+
handle_errors do
|
|
39
|
+
render(store.find(space)) do |sp|
|
|
40
|
+
supervisor = Space::Architect::Research::Supervisor.new(space: sp)
|
|
41
|
+
entries = supervisor.status
|
|
42
|
+
if entries.empty?
|
|
43
|
+
terminal.say "No research runs registered"
|
|
44
|
+
else
|
|
45
|
+
rows = entries.map do |e|
|
|
46
|
+
run = e[:run]
|
|
47
|
+
[run.id, run.pid.to_s, e[:state].to_s, run.model, e[:tail].last.to_s.slice(0, 60)]
|
|
48
|
+
end
|
|
49
|
+
terminal.say terminal.table(%w[ID PID State Model LastLine], rows)
|
|
50
|
+
end
|
|
51
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class Wait < BaseCommand
|
|
58
|
+
desc "Wait for all dispatched research runs to complete"
|
|
59
|
+
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
60
|
+
option :quiet, type: :boolean, default: false,
|
|
61
|
+
desc: "L0: suppress all output; exit status only"
|
|
62
|
+
option :level, type: :integer, default: 1,
|
|
63
|
+
desc: "Verbosity level: 1=lifecycle 2=+text 3=+tools 4=+io"
|
|
64
|
+
option :thinking, type: :boolean, default: false,
|
|
65
|
+
desc: "Show assistant thinking blocks"
|
|
66
|
+
option :jsonl, type: :boolean, default: false,
|
|
67
|
+
desc: "Emit raw lane-tagged JSONL (mutually exclusive with level/quiet)"
|
|
68
|
+
|
|
69
|
+
def call(space: nil, quiet: false, level: 1, thinking: false, jsonl: false, **opts)
|
|
70
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
71
|
+
handle_errors do
|
|
72
|
+
render(store.find(space)) do |sp|
|
|
73
|
+
supervisor = Space::Architect::Research::Supervisor.new(space: sp)
|
|
74
|
+
result = supervisor.wait(
|
|
75
|
+
quiet: quiet,
|
|
76
|
+
level: level.to_i,
|
|
77
|
+
thinking: thinking,
|
|
78
|
+
jsonl: jsonl
|
|
79
|
+
)
|
|
80
|
+
CLI.record_outcome(Outcome.new(exit_code: result == :ok ? 0 : 1))
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
Space::Architect::CLI::Registry.register "research" do |r|
|
|
91
|
+
r.register "dispatch", Space::Architect::CLI::Architect::Research::Dispatch
|
|
92
|
+
r.register "status", Space::Architect::CLI::Architect::Research::Status
|
|
93
|
+
r.register "wait", Space::Architect::CLI::Architect::Research::Wait
|
|
94
|
+
end
|
|
@@ -1,35 +1,29 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
r.register "resolve", SpaceArchitect::CLI::Repo::Resolve
|
|
29
|
-
end
|
|
30
|
-
prefix.register "shell" do |s|
|
|
31
|
-
s.register "init", SpaceArchitect::CLI::Shell::ShellInit
|
|
32
|
-
s.register "fish", SpaceArchitect::CLI::Shell::Fish
|
|
33
|
-
s.register "complete", SpaceArchitect::CLI::Shell::Complete
|
|
3
|
+
require "space_core/cli"
|
|
4
|
+
|
|
5
|
+
module Space::Architect
|
|
6
|
+
module CLI
|
|
7
|
+
# Exit-code bridge to the Space::Core CLI engine.
|
|
8
|
+
# `architect space <args>` (and `exe/space <args>` via Space::Core::CLI directly)
|
|
9
|
+
# hands the raw remainder to Space::Core's own dry-cli registry and translates
|
|
10
|
+
# Space::Core's recorded Outcome into the host exit code.
|
|
11
|
+
# Space::Core has its own Registry, Outcome, and :space_core_cli_outcome thread-local;
|
|
12
|
+
# this is the seam between the two registries (NOT a re-registration).
|
|
13
|
+
def self.dispatch_space(rest, out = $stdout, err = $stderr)
|
|
14
|
+
if ::Space::Core::CLI::TOP_LEVEL_HELP.include?(rest)
|
|
15
|
+
out.puts Dry::CLI::Usage.call(::Space::Core::CLI::Registry.get([]))
|
|
16
|
+
return 0
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if ::Space::Core::CLI::VERSION_REQUEST.include?(rest)
|
|
20
|
+
out.puts ::Space::Core::VERSION
|
|
21
|
+
return 0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
Thread.current[:space_core_cli_outcome] = nil
|
|
25
|
+
Dry::CLI.new(::Space::Core::CLI::Registry).call(arguments: rest, out: out, err: err)
|
|
26
|
+
::Space::Core::CLI.last_outcome&.exit_code || 0
|
|
27
|
+
end
|
|
34
28
|
end
|
|
35
29
|
end
|
|
@@ -1,32 +1,38 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
3
|
+
require "space_src/cli"
|
|
4
4
|
|
|
5
|
-
module
|
|
5
|
+
module Space::Architect
|
|
6
6
|
module CLI
|
|
7
|
-
# Exit-code bridge to the
|
|
8
|
-
# `architect src <args>` hands the raw remainder to
|
|
9
|
-
# registry and translates
|
|
10
|
-
#
|
|
11
|
-
# this is the seam between the two registries (NOT a re-registration).
|
|
7
|
+
# Exit-code bridge to the Space::Src CLI engine.
|
|
8
|
+
# `architect src <args>` hands the raw remainder to Space::Src's own dry-cli
|
|
9
|
+
# registry and translates Space::Src's recorded Outcome into the host exit code.
|
|
10
|
+
# Space::Src has its own Registry, Outcome, and :space_src_cli_* thread-locals;
|
|
11
|
+
# this is the seam between the two registries (NOT a re-registration). Space::Src's
|
|
12
12
|
# top-level help/version interceptors call Kernel.exit, so we reproduce that
|
|
13
13
|
# interception here against the injected IO instead of delegating to them.
|
|
14
14
|
# dry-cli's internal exit on a bare group / unknown command propagates as
|
|
15
15
|
# SystemExit — same as the host's own bare groups (e.g. `space repo`) — and is
|
|
16
16
|
# intentionally NOT rescued (accepted behavior change).
|
|
17
17
|
def self.dispatch_src(rest, out = $stdout, err = $stderr)
|
|
18
|
-
if
|
|
19
|
-
out.puts Dry::CLI::Usage.call(
|
|
18
|
+
if ::Space::Src::CLI::TOP_LEVEL_HELP.include?(rest)
|
|
19
|
+
out.puts Dry::CLI::Usage.call(::Space::Src::CLI::Registry.get([]))
|
|
20
20
|
return 0
|
|
21
21
|
end
|
|
22
|
-
if
|
|
23
|
-
out.puts
|
|
22
|
+
if ::Space::Src::CLI::VERSION_REQUEST.include?(rest)
|
|
23
|
+
out.puts ::Space::Src::VERSION
|
|
24
24
|
return 0
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
if ::Space::Src::CLI.bare_query?(rest)
|
|
28
|
+
paths = ::Space::Src::CLI.make_paths
|
|
29
|
+
config = ::Space::Src::Config::Store.load(paths.config_file).success
|
|
30
|
+
return ::Space::Src::Nav.dispatch(rest[0], out, err, config.base_dir)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Thread.current[:space_src_cli_outcome] = nil
|
|
34
|
+
Dry::CLI.new(::Space::Src::CLI::Registry).call(arguments: rest, out: out, err: err)
|
|
35
|
+
::Space::Src::CLI.last_outcome&.exit_code || 0
|
|
30
36
|
end
|
|
31
37
|
end
|
|
32
38
|
end
|