space-architect 1.3.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 -155
- 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 +92 -132
- 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 +81 -79
- data/lib/space_architect.rb +5 -20
- 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 +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 +2 -2
- data/skill/architect/research.md +46 -37
- metadata +115 -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 -44
|
@@ -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,10 +332,7 @@ module SpaceArchitect
|
|
|
348
332
|
end
|
|
349
333
|
end
|
|
350
334
|
|
|
351
|
-
class InstallSkills <
|
|
352
|
-
include GlobalOptions
|
|
353
|
-
include Helpers
|
|
354
|
-
|
|
335
|
+
class InstallSkills < BaseCommand
|
|
355
336
|
desc "Install bundled skills (architect, architect-research, architect-vocabulary) for a harness"
|
|
356
337
|
option :provider, default: "claude", desc: "Harness: claude, codex, opencode, pi"
|
|
357
338
|
option :project, type: :boolean, default: false, desc: "Install to CWD instead of global"
|
|
@@ -373,34 +354,8 @@ module SpaceArchitect
|
|
|
373
354
|
end
|
|
374
355
|
end
|
|
375
356
|
|
|
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
357
|
module Worktree
|
|
400
|
-
class Add <
|
|
401
|
-
include GlobalOptions
|
|
402
|
-
include Helpers
|
|
403
|
-
|
|
358
|
+
class Add < BaseCommand
|
|
404
359
|
desc "Create a worktree for a lane"
|
|
405
360
|
argument :repo, required: true, desc: "Repo name (under repos/)"
|
|
406
361
|
argument :iteration, required: true, desc: "Iteration name"
|
|
@@ -427,10 +382,7 @@ module SpaceArchitect
|
|
|
427
382
|
end
|
|
428
383
|
end
|
|
429
384
|
|
|
430
|
-
class Remove <
|
|
431
|
-
include GlobalOptions
|
|
432
|
-
include Helpers
|
|
433
|
-
|
|
385
|
+
class Remove < BaseCommand
|
|
434
386
|
desc "Remove a lane worktree"
|
|
435
387
|
argument :iteration, required: true, desc: "Iteration name"
|
|
436
388
|
argument :lane, required: true, desc: "Lane name"
|
|
@@ -448,10 +400,7 @@ module SpaceArchitect
|
|
|
448
400
|
end
|
|
449
401
|
end
|
|
450
402
|
|
|
451
|
-
class List <
|
|
452
|
-
include GlobalOptions
|
|
453
|
-
include Helpers
|
|
454
|
-
|
|
403
|
+
class List < BaseCommand
|
|
455
404
|
desc "List active architect worktrees"
|
|
456
405
|
|
|
457
406
|
def call(**opts)
|
|
@@ -473,10 +422,7 @@ module SpaceArchitect
|
|
|
473
422
|
end
|
|
474
423
|
|
|
475
424
|
module Variant
|
|
476
|
-
class Add <
|
|
477
|
-
include GlobalOptions
|
|
478
|
-
include Helpers
|
|
479
|
-
|
|
425
|
+
class Add < BaseCommand
|
|
480
426
|
desc "Create a variant set (competing lanes over one frozen spec)"
|
|
481
427
|
argument :repo, required: true, desc: "Repo name (under repos/)"
|
|
482
428
|
argument :iteration, required: true, desc: "Iteration name"
|
|
@@ -506,10 +452,7 @@ module SpaceArchitect
|
|
|
506
452
|
end
|
|
507
453
|
end
|
|
508
454
|
|
|
509
|
-
class Promote <
|
|
510
|
-
include GlobalOptions
|
|
511
|
-
include Helpers
|
|
512
|
-
|
|
455
|
+
class Promote < BaseCommand
|
|
513
456
|
desc "Promote one variant of a variant set as the winner"
|
|
514
457
|
argument :iteration, required: true, desc: "Iteration name"
|
|
515
458
|
argument :winner, required: true, desc: "Variant lane name to promote (e.g. v02)"
|
|
@@ -532,10 +475,7 @@ module SpaceArchitect
|
|
|
532
475
|
end
|
|
533
476
|
end
|
|
534
477
|
|
|
535
|
-
class Compare <
|
|
536
|
-
include GlobalOptions
|
|
537
|
-
include Helpers
|
|
538
|
-
|
|
478
|
+
class Compare < BaseCommand
|
|
539
479
|
desc "Compare variants of an iteration's variant set (read-only)"
|
|
540
480
|
argument :iteration, required: true, desc: "Iteration name"
|
|
541
481
|
argument :space, required: false, desc: "Space identifier (default: $PWD)"
|
|
@@ -569,32 +509,52 @@ module SpaceArchitect
|
|
|
569
509
|
end
|
|
570
510
|
end
|
|
571
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
|
|
572
532
|
end
|
|
573
533
|
end
|
|
574
534
|
end
|
|
575
535
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
b.register "new",
|
|
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
|
|
590
550
|
end
|
|
591
|
-
|
|
592
|
-
wt.register "add",
|
|
593
|
-
wt.register "remove",
|
|
594
|
-
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
|
|
595
555
|
end
|
|
596
|
-
|
|
597
|
-
v.register "add",
|
|
598
|
-
v.register "promote",
|
|
599
|
-
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
|
|
600
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
|
data/lib/space_architect/cli.rb
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "dry/cli"
|
|
4
|
+
require "pastel"
|
|
5
|
+
require "space_core/cli"
|
|
4
6
|
|
|
5
|
-
module
|
|
7
|
+
module Space::Architect
|
|
6
8
|
module CLI
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
# Delegate the outcome seam to Space::Core::CLI so both architect commands
|
|
10
|
+
# (which call CLI.record_outcome lexically) and the moved Helpers (which call
|
|
11
|
+
# CLI.record_outcome with Space::Core::CLI as lexical root) share one slot.
|
|
12
|
+
Outcome = Space::Core::CLI::Outcome
|
|
13
|
+
Helpers = Space::Core::CLI::Helpers
|
|
14
|
+
BaseCommand = Space::Core::CLI::BaseCommand
|
|
10
15
|
|
|
11
|
-
def self.record_outcome(o) = (
|
|
12
|
-
def self.last_outcome
|
|
16
|
+
def self.record_outcome(o) = Space::Core::CLI.record_outcome(o)
|
|
17
|
+
def self.last_outcome = Space::Core::CLI.last_outcome
|
|
13
18
|
|
|
14
19
|
module Registry
|
|
15
20
|
extend Dry::CLI::Registry
|
|
@@ -19,7 +24,8 @@ module SpaceArchitect
|
|
|
19
24
|
VERSION_REQUEST = [["version"], ["--version"]].freeze
|
|
20
25
|
|
|
21
26
|
def self.call(argv, out = $stdout, err = $stderr)
|
|
22
|
-
Thread.current[:
|
|
27
|
+
Thread.current[:space_core_cli_outcome] = nil
|
|
28
|
+
Space::Core::CLI.help_pastel = Pastel.new(enabled: Space::Core::CLI.help_colors?(argv, out, err))
|
|
23
29
|
|
|
24
30
|
if TOP_LEVEL_HELP.include?(argv)
|
|
25
31
|
out.puts Dry::CLI::Usage.call(Registry.get([]))
|
|
@@ -27,7 +33,7 @@ module SpaceArchitect
|
|
|
27
33
|
end
|
|
28
34
|
|
|
29
35
|
if VERSION_REQUEST.include?(argv)
|
|
30
|
-
out.puts
|
|
36
|
+
out.puts Space::Core::VERSION
|
|
31
37
|
return 0
|
|
32
38
|
end
|
|
33
39
|
|
|
@@ -35,7 +41,13 @@ module SpaceArchitect
|
|
|
35
41
|
return dispatch_src(argv[1..], out, err)
|
|
36
42
|
end
|
|
37
43
|
|
|
38
|
-
|
|
44
|
+
normalized = normalize_args(argv)
|
|
45
|
+
|
|
46
|
+
if normalized.first == "space"
|
|
47
|
+
return dispatch_space(normalized[1..], out, err)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
Dry::CLI.new(Registry).call(arguments: normalized, out: out, err: err)
|
|
39
51
|
last_outcome&.exit_code || 0
|
|
40
52
|
end
|
|
41
53
|
|
|
@@ -84,19 +96,7 @@ module SpaceArchitect
|
|
|
84
96
|
end
|
|
85
97
|
end
|
|
86
98
|
|
|
87
|
-
require_relative "cli/options"
|
|
88
|
-
require_relative "cli/helpers"
|
|
89
|
-
require_relative "cli/init"
|
|
90
|
-
require_relative "cli/new"
|
|
91
|
-
require_relative "cli/list"
|
|
92
|
-
require_relative "cli/show"
|
|
93
|
-
require_relative "cli/path"
|
|
94
|
-
require_relative "cli/use"
|
|
95
|
-
require_relative "cli/current"
|
|
96
|
-
require_relative "cli/status"
|
|
97
|
-
require_relative "cli/config"
|
|
98
|
-
require_relative "cli/repo"
|
|
99
|
-
require_relative "cli/shell"
|
|
100
99
|
require_relative "cli/architect"
|
|
101
100
|
require_relative "cli/space"
|
|
102
101
|
require_relative "cli/src"
|
|
102
|
+
require_relative "cli/research"
|