space-architect 8.0.0 → 9.1.0

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.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +54 -0
  3. data/README.md +39 -464
  4. data/lib/space_architect/architect_project.rb +90 -39
  5. data/lib/space_architect/bug_report.rb +2 -1
  6. data/lib/space_architect/cli/architect.rb +189 -11
  7. data/lib/space_architect/cli/research.rb +1 -1
  8. data/lib/space_architect/cli.rb +9 -14
  9. data/lib/space_architect/loop_cost.rb +592 -0
  10. data/lib/space_architect/research/supervisor.rb +9 -2
  11. data/lib/space_architect/routing.rb +149 -0
  12. data/lib/space_architect/session_sync/bin_path.rb +1 -1
  13. data/lib/space_architect/session_sync/cursor.rb +1 -1
  14. data/lib/space_architect/session_sync/plist.rb +1 -1
  15. data/lib/{space_core → space_architect}/version.rb +2 -2
  16. data/lib/space_architect.rb +2 -1
  17. data/skill/architect/SKILL.md +3 -2
  18. data/skill/architect-vocabulary/SKILL.md +2 -2
  19. metadata +20 -177
  20. data/exe/space +0 -13
  21. data/exe/src +0 -13
  22. data/lib/space_architect/cli/space.rb +0 -29
  23. data/lib/space_architect/cli/src.rb +0 -38
  24. data/lib/space_core/atomic_write.rb +0 -21
  25. data/lib/space_core/cli/base_command.rb +0 -19
  26. data/lib/space_core/cli/build.rb +0 -27
  27. data/lib/space_core/cli/config.rb +0 -49
  28. data/lib/space_core/cli/current.rb +0 -16
  29. data/lib/space_core/cli/help.rb +0 -195
  30. data/lib/space_core/cli/helpers.rb +0 -115
  31. data/lib/space_core/cli/init.rb +0 -29
  32. data/lib/space_core/cli/list.rb +0 -24
  33. data/lib/space_core/cli/loop_status.rb +0 -47
  34. data/lib/space_core/cli/new.rb +0 -38
  35. data/lib/space_core/cli/pack.rb +0 -29
  36. data/lib/space_core/cli/path.rb +0 -16
  37. data/lib/space_core/cli/repeatable_options.rb +0 -84
  38. data/lib/space_core/cli/repo.rb +0 -76
  39. data/lib/space_core/cli/run.rb +0 -44
  40. data/lib/space_core/cli/shell.rb +0 -125
  41. data/lib/space_core/cli/show.rb +0 -21
  42. data/lib/space_core/cli/status.rb +0 -74
  43. data/lib/space_core/cli/use.rb +0 -17
  44. data/lib/space_core/cli.rb +0 -177
  45. data/lib/space_core/commands.rb +0 -51
  46. data/lib/space_core/config.rb +0 -152
  47. data/lib/space_core/errors.rb +0 -14
  48. data/lib/space_core/git_client.rb +0 -49
  49. data/lib/space_core/mise_client.rb +0 -37
  50. data/lib/space_core/oci_builder.rb +0 -56
  51. data/lib/space_core/oci_packer.rb +0 -103
  52. data/lib/space_core/oci_runner.rb +0 -89
  53. data/lib/space_core/paths.rb +0 -58
  54. data/lib/space_core/repo_reference.rb +0 -19
  55. data/lib/space_core/repo_resolver.rb +0 -167
  56. data/lib/space_core/shell_integration.rb +0 -438
  57. data/lib/space_core/slugger.rb +0 -16
  58. data/lib/space_core/space.rb +0 -174
  59. data/lib/space_core/space_store.rb +0 -319
  60. data/lib/space_core/state.rb +0 -86
  61. data/lib/space_core/templates/oci/dockerfile.erb +0 -73
  62. data/lib/space_core/templates/oci/dockerignore.erb +0 -17
  63. data/lib/space_core/templates/oci/entrypoint.sh.erb +0 -16
  64. data/lib/space_core/terminal.rb +0 -161
  65. data/lib/space_core/warnings.rb +0 -13
  66. data/lib/space_core/xdg.rb +0 -33
  67. data/lib/space_core.rb +0 -26
  68. data/lib/space_src/cli/clone.rb +0 -54
  69. data/lib/space_src/cli/config.rb +0 -65
  70. data/lib/space_src/cli/daemon.rb +0 -362
  71. data/lib/space_src/cli/options.rb +0 -21
  72. data/lib/space_src/cli/org.rb +0 -199
  73. data/lib/space_src/cli/repo.rb +0 -169
  74. data/lib/space_src/cli/shell.rb +0 -121
  75. data/lib/space_src/cli/status.rb +0 -75
  76. data/lib/space_src/cli/sync.rb +0 -161
  77. data/lib/space_src/cli.rb +0 -159
  78. data/lib/space_src/cloner.rb +0 -77
  79. data/lib/space_src/config/contract.rb +0 -54
  80. data/lib/space_src/config/duration.rb +0 -79
  81. data/lib/space_src/config/model.rb +0 -49
  82. data/lib/space_src/config/store.rb +0 -156
  83. data/lib/space_src/forge/client.rb +0 -31
  84. data/lib/space_src/forge/github.rb +0 -98
  85. data/lib/space_src/launchd/agent.rb +0 -195
  86. data/lib/space_src/launchd/plist.rb +0 -129
  87. data/lib/space_src/log_rotator.rb +0 -46
  88. data/lib/space_src/migration.rb +0 -43
  89. data/lib/space_src/nav.rb +0 -99
  90. data/lib/space_src/paths.rb +0 -72
  91. data/lib/space_src/scm/client.rb +0 -87
  92. data/lib/space_src/scm/git.rb +0 -232
  93. data/lib/space_src/scm/status.rb +0 -24
  94. data/lib/space_src/shell.rb +0 -90
  95. data/lib/space_src/shell_integration.rb +0 -321
  96. data/lib/space_src/state/lock.rb +0 -59
  97. data/lib/space_src/state/store.rb +0 -140
  98. data/lib/space_src/sync/engine.rb +0 -503
  99. data/lib/space_src/sync/repo_plan.rb +0 -215
  100. data/lib/space_src/sync/report.rb +0 -18
  101. data/lib/space_src/ui/interactive_reporter.rb +0 -280
  102. data/lib/space_src/ui/json_reporter.rb +0 -39
  103. data/lib/space_src/ui/mode.rb +0 -68
  104. data/lib/space_src/ui/plain_reporter.rb +0 -53
  105. data/lib/space_src/ui/reporter.rb +0 -48
  106. data/lib/space_src/version.rb +0 -7
  107. data/lib/space_src.rb +0 -38
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "pathname"
5
+
6
+ module Space::Architect
7
+ # The v1 `architect.yaml` loop-role routing contract — the parity twin of the
8
+ # pi extension's parser (the extension's behavior defines v1; the one
9
+ # deliberate addition this iteration is `thinking` VALUE validation, landed on
10
+ # both sides). Pure module: parse one file's text, resolve the merged routing
11
+ # for a space, nil when no config exists anywhere. Every invalid state raises
12
+ # Space::Core::Error in the CLI's idiom, naming the file, the key, and the
13
+ # expectation. Resolution layers are [global, space-local], merged per role
14
+ # key; global is ENV["SPACE_ARCHITECT_GLOBAL_CONFIG"] if set, else
15
+ # ~/.config/space-architect/architect.yaml (exactly the extension's
16
+ # resolution — parity outranks the XDG convention, do not divert to
17
+ # XDG_CONFIG_HOME); space-local is architect.yaml beside the loaded
18
+ # space.yaml (the CLI already resolved the space — no walk-up).
19
+ module Routing
20
+ ROLES = %w[architect spec builder judge coordinator].freeze
21
+ # The four agent roles that must be routed after the merge; `architect` is optional.
22
+ REQUIRED_ROLES = %w[spec builder judge coordinator].freeze
23
+ ENTRY_KEYS = %w[model thinking].freeze
24
+
25
+ def self.global_path
26
+ env = ENV["SPACE_ARCHITECT_GLOBAL_CONFIG"]
27
+ return Pathname.new(env) unless env.nil?
28
+ Pathname.new("~/.config/space-architect/architect.yaml").expand_path
29
+ end
30
+
31
+ def self.space_path(space_dir)
32
+ Pathname.new(space_dir).join("architect.yaml")
33
+ end
34
+
35
+ # Parse one file's text into { role => {"model" => id, "thinking" => level|nil} }.
36
+ # +path+ is used only in error messages. Frozen v1 rules: integer version 1,
37
+ # the five known roles, entries ⊆ {model, thinking} with a non-empty model,
38
+ # duplicate mapping keys rejected (psych's plain load silently keeps the
39
+ # last — the npm yaml the extension parses with throws), aliases accepted,
40
+ # a trailing :level suffix on model parsed via Harness.parse_model_suffix
41
+ # and beating the thinking key.
42
+ def self.parse(text, path)
43
+ assert_unique_keys!(text, path)
44
+ doc = YAML.safe_load(text, aliases: true)
45
+ unless doc.is_a?(Hash)
46
+ raise Space::Core::Error, "architect.yaml (#{path}): <top> — expected a YAML mapping, got #{doc.inspect}"
47
+ end
48
+ version = doc["version"]
49
+ unless version.is_a?(Integer) && version == 1
50
+ raise Space::Core::Error, "architect.yaml (#{path}): version — expected integer 1, got #{version.inspect}"
51
+ end
52
+ roles = doc["roles"]
53
+ unless roles.is_a?(Hash)
54
+ raise Space::Core::Error, "architect.yaml (#{path}): roles — expected a mapping of role → entry, got #{roles.inspect}"
55
+ end
56
+
57
+ parsed = {}
58
+ roles.each do |role, entry|
59
+ unless ROLES.include?(role)
60
+ raise Space::Core::Error,
61
+ "architect.yaml (#{path}): roles.#{role} — expected one of #{ROLES.join('|')}, got #{role.inspect}"
62
+ end
63
+ unless entry.is_a?(Hash)
64
+ raise Space::Core::Error,
65
+ "architect.yaml (#{path}): roles.#{role} — expected a {model, thinking?} mapping, got #{entry.inspect}"
66
+ end
67
+ entry.each_key do |entry_key|
68
+ unless ENTRY_KEYS.include?(entry_key)
69
+ raise Space::Core::Error,
70
+ "architect.yaml (#{path}): roles.#{role}.#{entry_key} — expected one of #{ENTRY_KEYS.join('|')}, got #{entry_key.inspect}"
71
+ end
72
+ end
73
+ raw_model = entry["model"]
74
+ unless raw_model.is_a?(String) && !raw_model.strip.empty?
75
+ raise Space::Core::Error,
76
+ "architect.yaml (#{path}): roles.#{role}.model — expected non-empty 'provider/model-id[:level]', got #{raw_model.inspect}"
77
+ end
78
+ model, suffix_level = Harness.parse_model_suffix(raw_model.strip)
79
+
80
+ thinking = nil
81
+ if entry.key?("thinking")
82
+ raw_thinking = entry["thinking"]
83
+ # psych implements YAML 1.1, where a bare `off` is boolean false; the
84
+ # extension's YAML 1.2 parser reads it as the string "off". Coerce so
85
+ # `thinking: off` parses identically on both sides.
86
+ raw_thinking = "off" if raw_thinking == false
87
+ unless raw_thinking.is_a?(String) && Harness::THINKING_LEVELS.include?(raw_thinking.strip)
88
+ raise Space::Core::Error,
89
+ "architect.yaml (#{path}): roles.#{role}.thinking — expected one of " \
90
+ "#{Harness::THINKING_LEVELS.join('|')}, got #{entry['thinking'].inspect}"
91
+ end
92
+ thinking = raw_thinking.strip
93
+ end
94
+ parsed[role] = { "model" => model, "thinking" => suffix_level || thinking }
95
+ end
96
+ parsed
97
+ rescue Psych::Exception => e
98
+ raise Space::Core::Error, "architect.yaml (#{path}): malformed YAML — #{e.message}"
99
+ end
100
+
101
+ # The merged routing for a space: [global, space-local] merged per role key
102
+ # (a space file may override only builder and inherit the rest). nil when
103
+ # NEITHER file exists — no config is a normal state: no error, no side
104
+ # effects. Any found file that is malformed/invalid fails loud at parse;
105
+ # after the merge all four agent roles must be routed.
106
+ def self.for_space(space_dir)
107
+ global = global_path
108
+ local = space_path(space_dir)
109
+ found = [global, local].select { |p| File.file?(p.to_s) }
110
+ return nil if found.empty?
111
+
112
+ merged = {}
113
+ found.each { |p| merged.merge!(parse(File.read(p.to_s), p)) }
114
+ missing = REQUIRED_ROLES - merged.keys
115
+ if missing.any?
116
+ raise Space::Core::Error,
117
+ "architect.yaml (#{found.join(' + ')}): roles.#{missing.first} — expected all agent roles " \
118
+ "#{REQUIRED_ROLES.join('|')} to be routed, got (missing)"
119
+ end
120
+ merged
121
+ end
122
+
123
+ # Duplicate mapping keys anywhere in the document fail loud. Walks the psych
124
+ # node tree (a second, cheap parse) because YAML.safe_load cannot report them.
125
+ # An empty document parses to `false` (no root node) — skip the walk and let
126
+ # safe_load surface it as the loud not-a-mapping error.
127
+ def self.assert_unique_keys!(text, path)
128
+ tree = Psych.parse(text, filename: path.to_s)
129
+ return if tree == false
130
+ walk_unique_keys(tree.root, path)
131
+ end
132
+
133
+ def self.walk_unique_keys(node, path)
134
+ return unless node.is_a?(Psych::Nodes::Mapping) || node.is_a?(Psych::Nodes::Sequence)
135
+ if node.is_a?(Psych::Nodes::Mapping)
136
+ seen = {}
137
+ node.children.each_slice(2) do |key, _value| # paths:exempt — psych AST walk, not filesystem enumeration
138
+ next unless key.is_a?(Psych::Nodes::Scalar)
139
+ if seen[key.value]
140
+ raise Space::Core::Error,
141
+ "architect.yaml (#{path}): duplicate mapping key '#{key.value}' — map keys must be unique"
142
+ end
143
+ seen[key.value] = true
144
+ end
145
+ end
146
+ node.children.each { |child| walk_unique_keys(child, path) } # paths:exempt — psych AST walk, not filesystem enumeration
147
+ end
148
+ end
149
+ end
@@ -5,7 +5,7 @@ require "open3"
5
5
  module Space::Architect
6
6
  module SessionSync
7
7
  # Resolves the absolute path to the `architect` executable the plist
8
- # should invoke, imitating Space::Src::CLI::Daemon::Helpers::Resolve's
8
+ # should invoke, imitating RepoTender::CLI::Daemon::Helpers::Resolve's
9
9
  # detect_bin_path precedence: an env override (tests), the dev checkout's
10
10
  # exe/architect, `which architect`, then the installed gem's bin.
11
11
  module BinPath
@@ -6,7 +6,7 @@ require "fileutils"
6
6
  module Space::Architect
7
7
  module SessionSync
8
8
  # Machine-managed cursor at $XDG_STATE_HOME/space-architect/session-sync.yaml
9
- # (imitates Space::Src::State::Store's load/write/emit shape). Keyed by
9
+ # (imitates RepoTender::State::Store's load/write/emit shape). Keyed by
10
10
  # absolute source path; each entry records the size + mtime observed the
11
11
  # last time that file was uploaded.
12
12
  class Cursor
@@ -3,7 +3,7 @@
3
3
  module Space::Architect
4
4
  module SessionSync
5
5
  # Hand-rolled launchd plist emitter for the session-sync agent, imitating
6
- # Space::Src::Launchd::Plist's shape. Under launchd's bare PATH, a bare
6
+ # RepoTender::Launchd::Plist's shape. Under launchd's bare PATH, a bare
7
7
  # env-relative ruby binstub shebang resolves to macOS system Ruby instead
8
8
  # of the caller's toolchain, so ProgramArguments names the interpreter
9
9
  # explicitly (ruby_bin) rather than relying on shebang resolution — no
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Space
4
- module Core
5
- VERSION = "8.0.0"
4
+ module Architect
5
+ VERSION = "9.1.0"
6
6
  end
7
7
  end
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "space_core"
4
- require "space_src"
4
+ require_relative "space_architect/version"
5
5
 
6
6
  require_relative "space_architect/harness"
7
+ require_relative "space_architect/routing"
7
8
  require_relative "space_architect/run_creator"
8
9
  require_relative "space_architect/gate_lint"
9
10
  require_relative "space_architect/gate_evaluator"
@@ -151,8 +151,9 @@ loop.
151
151
  an iteration index pointing at each iteration file; per-iteration detail lives
152
152
  in the iteration file, never duplicated into the handoff. `architect status`
153
153
  prints project state (iterations, freeze_shas, lanes, verdicts) at any point.
154
- - **Space setup (first time):** `architect space new "Project Name" -r org/repo -r …`
155
- (each repo is a repeatable `-r` flag after the title), then `architect init` inside
154
+ - **Space setup (first time):** `space new "Project Name" -r org/repo -r …`
155
+ (the space-cadet binary; each repo is a repeatable `-r` flag after the title),
156
+ then `architect init` inside
156
157
  the space to scaffold `architecture/ARCHITECT.md`.
157
158
  - Scale to the task: trivial fixes don't need the loop — say so and let the
158
159
  human do it inline or in a normal session. The loop is for iteration-sized
@@ -131,8 +131,8 @@ Safe **read-only** commands to orient yourself (these don't run the loop):
131
131
 
132
132
  ```sh
133
133
  architect status # project state: iterations, freeze shas, lanes, verdicts
134
- architect space show # the space you're standing in
135
- architect space list # all your spaces
134
+ space show # the space you're standing in (space-cadet binary)
135
+ space list # all your spaces
136
136
  ```
137
137
 
138
138
  ## Maintenance
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: space-architect
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.0.0
4
+ version: 9.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Jacobs
@@ -10,47 +10,47 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: async
13
+ name: space-cadet
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '2.39'
18
+ version: '9.1'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '2.39'
25
+ version: '9.1'
26
26
  - !ruby/object:Gem::Dependency
27
- name: async-process
27
+ name: async-http
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '1.4'
32
+ version: '0.95'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.4'
39
+ version: '0.95'
40
40
  - !ruby/object:Gem::Dependency
41
- name: async-http
41
+ name: async-process
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.95'
46
+ version: '1.4'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0.95'
53
+ version: '1.4'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: protocol-http
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -107,48 +107,6 @@ dependencies:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
109
  version: '1.10'
110
- - !ruby/object:Gem::Dependency
111
- name: dry-schema
112
- requirement: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - "~>"
115
- - !ruby/object:Gem::Version
116
- version: '1.16'
117
- type: :runtime
118
- prerelease: false
119
- version_requirements: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - "~>"
122
- - !ruby/object:Gem::Version
123
- version: '1.16'
124
- - !ruby/object:Gem::Dependency
125
- name: dry-struct
126
- requirement: !ruby/object:Gem::Requirement
127
- requirements:
128
- - - "~>"
129
- - !ruby/object:Gem::Version
130
- version: '1.8'
131
- type: :runtime
132
- prerelease: false
133
- version_requirements: !ruby/object:Gem::Requirement
134
- requirements:
135
- - - "~>"
136
- - !ruby/object:Gem::Version
137
- version: '1.8'
138
- - !ruby/object:Gem::Dependency
139
- name: dry-types
140
- requirement: !ruby/object:Gem::Requirement
141
- requirements:
142
- - - "~>"
143
- - !ruby/object:Gem::Version
144
- version: '1.9'
145
- type: :runtime
146
- prerelease: false
147
- version_requirements: !ruby/object:Gem::Requirement
148
- requirements:
149
- - - "~>"
150
- - !ruby/object:Gem::Version
151
- version: '1.9'
152
110
  - !ruby/object:Gem::Dependency
153
111
  name: dry-validation
154
112
  requirement: !ruby/object:Gem::Requirement
@@ -163,34 +121,6 @@ dependencies:
163
121
  - - "~>"
164
122
  - !ruby/object:Gem::Version
165
123
  version: '1.11'
166
- - !ruby/object:Gem::Dependency
167
- name: xdg
168
- requirement: !ruby/object:Gem::Requirement
169
- requirements:
170
- - - "~>"
171
- - !ruby/object:Gem::Version
172
- version: '10.2'
173
- type: :runtime
174
- prerelease: false
175
- version_requirements: !ruby/object:Gem::Requirement
176
- requirements:
177
- - - "~>"
178
- - !ruby/object:Gem::Version
179
- version: '10.2'
180
- - !ruby/object:Gem::Dependency
181
- name: tty-cursor
182
- requirement: !ruby/object:Gem::Requirement
183
- requirements:
184
- - - "~>"
185
- - !ruby/object:Gem::Version
186
- version: '0.7'
187
- type: :runtime
188
- prerelease: false
189
- version_requirements: !ruby/object:Gem::Requirement
190
- requirements:
191
- - - "~>"
192
- - !ruby/object:Gem::Version
193
- version: '0.7'
194
124
  - !ruby/object:Gem::Dependency
195
125
  name: minitest
196
126
  requirement: !ruby/object:Gem::Requirement
@@ -233,16 +163,15 @@ dependencies:
233
163
  - - "~>"
234
164
  - !ruby/object:Gem::Version
235
165
  version: '13.0'
236
- description: 'A dry-cli CLI for spaces: date-prefixed directories with a YAML identity
237
- file, $PWD-based current-space resolution, and XDG config/state. Provisions repos
238
- at copy-on-write speed from evergreen checkouts, concurrently on fibers. Ships fish
239
- shell integration and completions.'
166
+ description: 'A dry-cli CLI for the Architect Loop: iterations, briefs, freezes, verdicts,
167
+ lane worktrees, and headless pi dispatch — the judgment loop that runs inside space-cadet''s
168
+ task-scoped workspaces. Depends on the space-cadet gem for the spaces substrate
169
+ (hard) and the repo-tender gem for the session-sync launchd agent (soft, install
170
+ at will).'
240
171
  email:
241
172
  - eric@ebj.dev
242
173
  executables:
243
174
  - architect
244
- - space
245
- - src
246
175
  extensions: []
247
176
  extra_rdoc_files: []
248
177
  files:
@@ -250,21 +179,18 @@ files:
250
179
  - LICENSE.txt
251
180
  - README.md
252
181
  - exe/architect
253
- - exe/space
254
- - exe/src
255
182
  - lib/space_architect.rb
256
183
  - lib/space_architect/architect_project.rb
257
184
  - lib/space_architect/bug_report.rb
258
185
  - lib/space_architect/cli.rb
259
186
  - lib/space_architect/cli/architect.rb
260
187
  - lib/space_architect/cli/research.rb
261
- - lib/space_architect/cli/space.rb
262
- - lib/space_architect/cli/src.rb
263
188
  - lib/space_architect/conversations_client.rb
264
189
  - lib/space_architect/gate_evaluator.rb
265
190
  - lib/space_architect/gate_lint.rb
266
191
  - lib/space_architect/harness.rb
267
192
  - lib/space_architect/jobs_client.rb
193
+ - lib/space_architect/loop_cost.rb
268
194
  - lib/space_architect/pi/builder-guard.ts
269
195
  - lib/space_architect/research.rb
270
196
  - lib/space_architect/research/mux.rb
@@ -273,6 +199,7 @@ files:
273
199
  - lib/space_architect/research/renderer.rb
274
200
  - lib/space_architect/research/run.rb
275
201
  - lib/space_architect/research/supervisor.rb
202
+ - lib/space_architect/routing.rb
276
203
  - lib/space_architect/run_creator.rb
277
204
  - lib/space_architect/session_sync.rb
278
205
  - lib/space_architect/session_sync/bin_path.rb
@@ -284,91 +211,7 @@ files:
284
211
  - lib/space_architect/templates/architect.md.erb
285
212
  - lib/space_architect/templates/brief.md.erb
286
213
  - lib/space_architect/templates/iteration.md.erb
287
- - lib/space_core.rb
288
- - lib/space_core/atomic_write.rb
289
- - lib/space_core/cli.rb
290
- - lib/space_core/cli/base_command.rb
291
- - lib/space_core/cli/build.rb
292
- - lib/space_core/cli/config.rb
293
- - lib/space_core/cli/current.rb
294
- - lib/space_core/cli/help.rb
295
- - lib/space_core/cli/helpers.rb
296
- - lib/space_core/cli/init.rb
297
- - lib/space_core/cli/list.rb
298
- - lib/space_core/cli/loop_status.rb
299
- - lib/space_core/cli/new.rb
300
- - lib/space_core/cli/pack.rb
301
- - lib/space_core/cli/path.rb
302
- - lib/space_core/cli/repeatable_options.rb
303
- - lib/space_core/cli/repo.rb
304
- - lib/space_core/cli/run.rb
305
- - lib/space_core/cli/shell.rb
306
- - lib/space_core/cli/show.rb
307
- - lib/space_core/cli/status.rb
308
- - lib/space_core/cli/use.rb
309
- - lib/space_core/commands.rb
310
- - lib/space_core/config.rb
311
- - lib/space_core/errors.rb
312
- - lib/space_core/git_client.rb
313
- - lib/space_core/mise_client.rb
314
- - lib/space_core/oci_builder.rb
315
- - lib/space_core/oci_packer.rb
316
- - lib/space_core/oci_runner.rb
317
- - lib/space_core/paths.rb
318
- - lib/space_core/repo_reference.rb
319
- - lib/space_core/repo_resolver.rb
320
- - lib/space_core/shell_integration.rb
321
- - lib/space_core/slugger.rb
322
- - lib/space_core/space.rb
323
- - lib/space_core/space_store.rb
324
- - lib/space_core/state.rb
325
- - lib/space_core/templates/oci/dockerfile.erb
326
- - lib/space_core/templates/oci/dockerignore.erb
327
- - lib/space_core/templates/oci/entrypoint.sh.erb
328
- - lib/space_core/terminal.rb
329
- - lib/space_core/version.rb
330
- - lib/space_core/warnings.rb
331
- - lib/space_core/xdg.rb
332
- - lib/space_src.rb
333
- - lib/space_src/cli.rb
334
- - lib/space_src/cli/clone.rb
335
- - lib/space_src/cli/config.rb
336
- - lib/space_src/cli/daemon.rb
337
- - lib/space_src/cli/options.rb
338
- - lib/space_src/cli/org.rb
339
- - lib/space_src/cli/repo.rb
340
- - lib/space_src/cli/shell.rb
341
- - lib/space_src/cli/status.rb
342
- - lib/space_src/cli/sync.rb
343
- - lib/space_src/cloner.rb
344
- - lib/space_src/config/contract.rb
345
- - lib/space_src/config/duration.rb
346
- - lib/space_src/config/model.rb
347
- - lib/space_src/config/store.rb
348
- - lib/space_src/forge/client.rb
349
- - lib/space_src/forge/github.rb
350
- - lib/space_src/launchd/agent.rb
351
- - lib/space_src/launchd/plist.rb
352
- - lib/space_src/log_rotator.rb
353
- - lib/space_src/migration.rb
354
- - lib/space_src/nav.rb
355
- - lib/space_src/paths.rb
356
- - lib/space_src/scm/client.rb
357
- - lib/space_src/scm/git.rb
358
- - lib/space_src/scm/status.rb
359
- - lib/space_src/shell.rb
360
- - lib/space_src/shell_integration.rb
361
- - lib/space_src/state/lock.rb
362
- - lib/space_src/state/store.rb
363
- - lib/space_src/sync/engine.rb
364
- - lib/space_src/sync/repo_plan.rb
365
- - lib/space_src/sync/report.rb
366
- - lib/space_src/ui/interactive_reporter.rb
367
- - lib/space_src/ui/json_reporter.rb
368
- - lib/space_src/ui/mode.rb
369
- - lib/space_src/ui/plain_reporter.rb
370
- - lib/space_src/ui/reporter.rb
371
- - lib/space_src/version.rb
214
+ - lib/space_architect/version.rb
372
215
  - skill/architect-research/SKILL.md
373
216
  - skill/architect-research/lanes.md
374
217
  - skill/architect-vocabulary/SKILL.md
@@ -397,6 +240,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
397
240
  requirements: []
398
241
  rubygems_version: 4.0.10
399
242
  specification_version: 4
400
- summary: Task-scoped project workspaces (repos · notes · artifacts under one self-describing
401
- root)
243
+ summary: The Architect Loop — structured judgment-and-build cycles for humans and
244
+ headless AI builders
402
245
  test_files: []
data/exe/space DELETED
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- source_gemfile = File.expand_path("../Gemfile", __dir__)
5
- if File.exist?(source_gemfile)
6
- ENV["BUNDLE_GEMFILE"] ||= source_gemfile
7
- require "bundler/setup"
8
- $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
9
- end
10
-
11
- require "space_core"
12
-
13
- Space::Core::CLI.run(ARGV, $stdout, $stderr)
data/exe/src DELETED
@@ -1,13 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- source_gemfile = File.expand_path("../Gemfile", __dir__)
5
- if File.exist?(source_gemfile)
6
- ENV["BUNDLE_GEMFILE"] ||= source_gemfile
7
- require "bundler/setup"
8
- $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
9
- end
10
-
11
- require "space_src"
12
-
13
- Space::Src::CLI.run(ARGV, $stdout, $stderr)
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
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
28
- end
29
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "space_src/cli"
4
-
5
- module Space::Architect
6
- module CLI
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
- # top-level help/version interceptors call Kernel.exit, so we reproduce that
13
- # interception here against the injected IO instead of delegating to them.
14
- # dry-cli's internal exit on a bare group / unknown command propagates as
15
- # SystemExit — same as the host's own bare groups (e.g. `space repo`) — and is
16
- # intentionally NOT rescued (accepted behavior change).
17
- def self.dispatch_src(rest, out = $stdout, err = $stderr)
18
- if ::Space::Src::CLI::TOP_LEVEL_HELP.include?(rest)
19
- out.puts Dry::CLI::Usage.call(::Space::Src::CLI::Registry.get([]))
20
- return 0
21
- end
22
- if ::Space::Src::CLI::VERSION_REQUEST.include?(rest)
23
- out.puts ::Space::Src::VERSION
24
- return 0
25
- end
26
-
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
36
- end
37
- end
38
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fileutils"
4
-
5
- module Space::Core
6
- module AtomicWrite
7
- module_function
8
-
9
- def write(path, content)
10
- path = path.to_s
11
- dir = File.dirname(path)
12
- FileUtils.mkdir_p(dir)
13
- tmp_path = File.join(dir, ".#{File.basename(path)}.#{Process.pid}.tmp")
14
-
15
- File.write(tmp_path, content)
16
- File.rename(tmp_path, path)
17
- ensure
18
- FileUtils.rm_f(tmp_path) if defined?(tmp_path) && tmp_path && File.exist?(tmp_path)
19
- end
20
- end
21
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dry/cli"
4
-
5
- module Space::Core::CLI
6
- # Base for every space/architect command. dry-cli (>= 0.7.0) copies a
7
- # superclass's options to its subclasses, so the global colour options are
8
- # declared once here and inherited everywhere instead of being mixed in per
9
- # command. Helpers (terminal/store/render) ride along by inheritance too.
10
- #
11
- # The `src` binary has its own output-mode system (--plain/--json) and does
12
- # NOT inherit from this base.
13
- class BaseCommand < Dry::CLI::Command
14
- include Helpers
15
-
16
- option :color, type: :string, default: "auto", desc: "Color output: auto, always, never"
17
- option :colors, type: :string, desc: "Alias for --color"
18
- end
19
- end