space-cadet 9.0.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +32 -0
- data/LICENSE.txt +21 -0
- data/README.md +279 -0
- data/exe/space +13 -0
- data/lib/space_core/atomic_write.rb +21 -0
- data/lib/space_core/cli/base_command.rb +19 -0
- data/lib/space_core/cli/build.rb +27 -0
- data/lib/space_core/cli/config.rb +49 -0
- data/lib/space_core/cli/current.rb +16 -0
- data/lib/space_core/cli/help.rb +195 -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/loop_status.rb +47 -0
- data/lib/space_core/cli/new.rb +38 -0
- data/lib/space_core/cli/pack.rb +29 -0
- data/lib/space_core/cli/path.rb +16 -0
- data/lib/space_core/cli/repeatable_options.rb +84 -0
- data/lib/space_core/cli/repo.rb +76 -0
- data/lib/space_core/cli/run.rb +44 -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 +74 -0
- data/lib/space_core/cli/use.rb +17 -0
- data/lib/space_core/cli.rb +177 -0
- data/lib/space_core/cloner.rb +77 -0
- data/lib/space_core/commands.rb +51 -0
- data/lib/space_core/config.rb +152 -0
- data/lib/space_core/errors.rb +14 -0
- data/lib/space_core/git_client.rb +49 -0
- data/lib/space_core/mise_client.rb +37 -0
- data/lib/space_core/oci_builder.rb +56 -0
- data/lib/space_core/oci_packer.rb +103 -0
- data/lib/space_core/oci_runner.rb +89 -0
- data/lib/space_core/paths.rb +58 -0
- data/lib/space_core/repo_reference.rb +19 -0
- data/lib/space_core/repo_resolver.rb +167 -0
- data/lib/space_core/scm/client.rb +87 -0
- data/lib/space_core/scm/git.rb +232 -0
- data/lib/space_core/scm/status.rb +24 -0
- data/lib/space_core/shell.rb +90 -0
- data/lib/space_core/shell_integration.rb +438 -0
- data/lib/space_core/slugger.rb +16 -0
- data/lib/space_core/space.rb +174 -0
- data/lib/space_core/space_store.rb +319 -0
- data/lib/space_core/state.rb +86 -0
- data/lib/space_core/templates/oci/dockerfile.erb +73 -0
- data/lib/space_core/templates/oci/dockerignore.erb +17 -0
- data/lib/space_core/templates/oci/entrypoint.sh.erb +16 -0
- data/lib/space_core/terminal.rb +161 -0
- data/lib/space_core/version.rb +7 -0
- data/lib/space_core/warnings.rb +13 -0
- data/lib/space_core/xdg.rb +33 -0
- data/lib/space_core.rb +26 -0
- metadata +199 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 43aad33181b2d51dcdf9a43b797325a90b513b2ea6b9d1aa5774b5c6d3e14fed
|
|
4
|
+
data.tar.gz: c63367116cb12fc23008af8f0be141b3e4d86db6bd90826c135000898eef5c89
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 50f518864108c2475262cf5931bff2af4cd79205961b7ff935ab187ccf15cfdaa9caa40f835e6926e169cc4f1ca3fdaf284cfea1b4b029598673fcf9de0fc1a2
|
|
7
|
+
data.tar.gz: 849789bb6f71eb569af79a1d5ed93dbd2c32c1510b8601180fea6ca4129e5d82e2118e8479c3baa2c4e185f1756663046d07fb1959c3634824ba09f5f8d5c9bf
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [9.0.0] - 2026-10-09
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Extracted from space-architect 8.0.0.** The space tool (`Space::Core`,
|
|
13
|
+
binary `space`) is split back out of
|
|
14
|
+
[jetpks/space-architect](https://github.com/jetpks/space-architect) into its
|
|
15
|
+
own repo, gem, and version line — undoing the v1.0.0-era absorption. The gem
|
|
16
|
+
is `space-cadet`, the binary is `space`, the module stays `Space::Core`, and
|
|
17
|
+
the version restarts at 9.0.0 (one major above the 8.x line it left).
|
|
18
|
+
- The fish shell integration's internals are renamed to the gem's own identity:
|
|
19
|
+
`__space_core_*` functions and the `__SPACE_CORE_VERSION__` compat-token
|
|
20
|
+
placeholder (was `__space_architect_*` / `__SPACE_ARCHITECT_VERSION__`).
|
|
21
|
+
Re-run `space shell fish install` after upgrading.
|
|
22
|
+
- XDG config/state now live under `~/.config/space-cadet/` and
|
|
23
|
+
`~/.local/state/space-cadet/` (was `space-architect/`). Run `space init` and
|
|
24
|
+
migrate any custom `config.yml`/`state.yml` across.
|
|
25
|
+
- The engine's subprocess shell, copy-on-write cloner, and git SCM seam
|
|
26
|
+
(`Space::Core::Shell`, `Space::Core::Cloner`, `Space::Core::SCM::*`) are
|
|
27
|
+
vendored into the gem — previously shared with the space-architect monolith's
|
|
28
|
+
`Space::Src` engine.
|
|
29
|
+
- Dependencies trimmed to exactly what the space tool requires: `async`,
|
|
30
|
+
`async-process`, `pastel`, `dry-cli`, `dry-monads`.
|
|
31
|
+
|
|
32
|
+
[9.0.0]: https://github.com/jetpks/space-cadet/blob/main/CHANGELOG.md
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eric
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# Space Cadet 🪐
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/rb/space-cadet)
|
|
4
|
+
|
|
5
|
+
> **Task-scoped project workspaces — for humans and their agents!** ✨🌌
|
|
6
|
+
|
|
7
|
+
`space-cadet` is a Ruby gem for **spaces** — task-scoped project workspaces
|
|
8
|
+
that hold repos, notes, and artifacts under one obvious filesystem root. One
|
|
9
|
+
binary, **`space`**, over the `Space::Core` library. It pairs with
|
|
10
|
+
[jetpks/space-architect](https://github.com/jetpks/space-architect) (the
|
|
11
|
+
Architect Loop, which runs on top of spaces) and
|
|
12
|
+
[jetpks/repo-tender](https://github.com/jetpks/repo-tender) (which tends the
|
|
13
|
+
evergreen checkouts spaces provision from).
|
|
14
|
+
|
|
15
|
+
**Lineage:** this repo is the space tool's original home (the v1.0.0 era); the
|
|
16
|
+
tool was absorbed into space-architect (up to 8.0.0) and is extracted back out
|
|
17
|
+
here as of 9.0.0.
|
|
18
|
+
|
|
19
|
+
## What's a space? 🪐
|
|
20
|
+
|
|
21
|
+
A space is just a regular directory with a tiny YAML identity file and room for
|
|
22
|
+
everything a task needs:
|
|
23
|
+
|
|
24
|
+
```text
|
|
25
|
+
~/architect/spaces/20260531-name-of-space/
|
|
26
|
+
space.yaml # identity: id, title, status, repos, notes, tags
|
|
27
|
+
README.md
|
|
28
|
+
repos/ # cloned (or copy-on-write'd) repositories
|
|
29
|
+
notes/ # scratch, prompts, logs
|
|
30
|
+
architecture/ # project files when the space runs an Architect project
|
|
31
|
+
build/ # OCI contexts + scratch (build/oci/)
|
|
32
|
+
tmp/ # workspace-local temp — use this instead of /tmp
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Run a command from anywhere inside a space and it just works — `space` walks up
|
|
36
|
+
from `$PWD` until it finds the nearest `space.yaml`. No "current space" state
|
|
37
|
+
to get out of sync; where you *are* is the space you mean. 🧭
|
|
38
|
+
|
|
39
|
+
## Installation 📦
|
|
40
|
+
|
|
41
|
+
Add it to your `Gemfile`:
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
gem "space-cadet"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
bundle install
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Or grab it yourself:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
gem install space-cadet
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The gem is `space-cadet`; it installs one executable, `space`. 🎀
|
|
58
|
+
|
|
59
|
+
## Quick start 🎀
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
space init # create XDG config + state files
|
|
63
|
+
space new "Name of Space" # blast off a new space 🚀
|
|
64
|
+
space new "Name of Space" -r org/repo -r org/lib # …with repos cloned in (repeat -r)
|
|
65
|
+
space list # see all your spaces
|
|
66
|
+
space show # show the space you're standing in
|
|
67
|
+
|
|
68
|
+
# Containers (run from inside a space) — a portable, reproducible-by-SHA image of the space
|
|
69
|
+
space pack # render build/oci/ (Dockerfile + entrypoint)
|
|
70
|
+
space build # pack + build & tag <space-id>:<git-sha>
|
|
71
|
+
space run # run it — login shell, auth from your env
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Commands 🌌
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
space init
|
|
78
|
+
space new "Name of Space"
|
|
79
|
+
space new "Name of Space" -r org/repo -r example-tools/alpha -r example-tools/beta
|
|
80
|
+
space list # alias: space ls
|
|
81
|
+
space show 20260531-name-of-space
|
|
82
|
+
space path 20260531-name-of-space
|
|
83
|
+
space current # based on $PWD
|
|
84
|
+
space show # based on $PWD
|
|
85
|
+
space status # report: metadata (+ project status when present)
|
|
86
|
+
space status 20260531-name-of-space # report another space
|
|
87
|
+
space status done # set: active | paused | done | archived
|
|
88
|
+
space status 20260531-name-of-space done
|
|
89
|
+
space config set default_provider github.com
|
|
90
|
+
space config set default_organization example-org
|
|
91
|
+
space repo add example-app # github.com/example-org/example-app
|
|
92
|
+
space repo add example-tools/alpha example-tools/beta
|
|
93
|
+
space repo add gitlab.com/example-org/api
|
|
94
|
+
space repo resolve example-app example-tools/async
|
|
95
|
+
space repo ls # alias: space repos ls
|
|
96
|
+
space use 20260531-name-of-space # records recent state, prints the path
|
|
97
|
+
space ls --color=always # auto | always | never (--colors also accepted)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`space status` is **report-or-set**: with no status keyword (bare, or with just
|
|
101
|
+
a space id) it *reports* the space — its metadata plus a compact project-status
|
|
102
|
+
block when the space declares one, quietly omitted otherwise; pass a status
|
|
103
|
+
keyword (`active`, `paused`, `done`, `archived`) to *set* it instead. 🔁
|
|
104
|
+
|
|
105
|
+
Repos are passed with a repeatable `-r` flag (`-r org/repo -r org/lib`); the
|
|
106
|
+
comma form (`-r a,b`) works too. Space ids are date-prefixed
|
|
107
|
+
(`20260531-name-of-space`) so they sort naturally, and duplicate names on the
|
|
108
|
+
same day get a counter (`…-name-of-space-2`). 📅
|
|
109
|
+
|
|
110
|
+
Full command reference: [docs/reference.md](docs/reference.md).
|
|
111
|
+
|
|
112
|
+
## Containerize a space: `pack` · `build` · `run` 📦
|
|
113
|
+
|
|
114
|
+
A space is self-describing enough to become a container. `space pack` renders a
|
|
115
|
+
portable OCI build context from the space; `space build` packs and builds it into
|
|
116
|
+
a **reproducible-by-SHA** image; `space run` runs that image with your auth
|
|
117
|
+
injected at runtime and stateful paths bind-mounted back to the host. 🐳
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
space pack # render build/oci/ (Dockerfile + entrypoint + ignore file)
|
|
121
|
+
space pack -o /tmp/ctx # …to a different output directory
|
|
122
|
+
space build # pack, then build & tag <space-id>:<git-sha> and :latest
|
|
123
|
+
space run # run <space-id>:latest — login shell, auth from your env
|
|
124
|
+
space run architect status # …or run a one-off command instead of the login shell
|
|
125
|
+
space run --tty # force an interactive TTY (default: auto-detect)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**What lands in the image.** The context copies the whole space tree (filtered by
|
|
129
|
+
a generated `Dockerfile.dockerignore`) onto a `ruby:4.0.5` base with `git`, the
|
|
130
|
+
Claude Code CLI, and the `space-cadet` gem — installed from the in-space
|
|
131
|
+
`repos/space-cadet` checkout when present (a pinned build), else from
|
|
132
|
+
RubyGems. Secrets never enter the layers: `.env`, `*.key`, `*.pem`, ssh keys,
|
|
133
|
+
`build/`, and `tmp/` are all excluded by the generated ignore file. 🔒
|
|
134
|
+
|
|
135
|
+
**Reproducible by SHA.** `space build` tags the image `<space-id>:<sha>`, where
|
|
136
|
+
`<sha>` is the space repo's 12-char `HEAD` (suffixed `-dirty` when the tree has
|
|
137
|
+
uncommitted changes), plus a moving `:latest`. Same commit → same tag → same
|
|
138
|
+
image. It drives the `container` CLI, but the output is an ordinary OCI/Docker
|
|
139
|
+
build context, so `docker build -f build/oci/Dockerfile .` (from the space root)
|
|
140
|
+
works just as well.
|
|
141
|
+
|
|
142
|
+
**Auth stays out of the layers.** `space run` injects only the auth environment
|
|
143
|
+
variables that are actually set — `ANTHROPIC_API_KEY`, `CLAUDE_CODE_OAUTH_TOKEN`,
|
|
144
|
+
`ANTHROPIC_BASE_URL` — with `-e` at run time, so credentials live in your shell,
|
|
145
|
+
never in the image. 🗝️
|
|
146
|
+
|
|
147
|
+
**Forwarding payload credentials.** Beyond the always-on auth trio, a space can declare
|
|
148
|
+
`run.env:` in `space.yaml` — a list of host env var names forwarded into the container at
|
|
149
|
+
run time. You can also pass `space run --env VAR` (repeatable) for ad hoc additions. All
|
|
150
|
+
forwarding is bare `-e VAR` passthrough: values never appear in argv, `ps`, or the image.
|
|
151
|
+
A requested-but-unset var warns on stderr instead of silently failing inside the guest.
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
run:
|
|
155
|
+
env: # run-time: host var names, forwarded as bare -e VAR
|
|
156
|
+
- FIREWORKS_API_KEY
|
|
157
|
+
- OPENAI_API_KEY
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Declaring provisioning & persistence** — two optional keys in `space.yaml`:
|
|
161
|
+
|
|
162
|
+
```yaml
|
|
163
|
+
pack:
|
|
164
|
+
provision: # build-time: relative scripts, baked in by `space build`
|
|
165
|
+
- scripts/setup-toolchain.sh
|
|
166
|
+
persist: # run-time: absolute guest paths, bind-mounted per run
|
|
167
|
+
- /root/.claude
|
|
168
|
+
- /root/.local/state
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
`provision` scripts must live under the space root and be executable. Each script is
|
|
172
|
+
copied into the image individually (`COPY <script> /space/<script>`) and then invoked
|
|
173
|
+
(`RUN /space/<script>`) **before** the full space tree lands and **before** the gem is
|
|
174
|
+
installed. This ordering is the cache-hygiene guarantee: editing any other space file
|
|
175
|
+
leaves the provision and gem-install layers cached, so a rebuild completes in seconds
|
|
176
|
+
instead of minutes. Scripts must therefore be self-contained — they run with only the
|
|
177
|
+
base system layers and any earlier provision scripts' outputs; they cannot read other
|
|
178
|
+
space files or call `space`. Scripts must have the executable bit set; COPY preserves
|
|
179
|
+
the mode from the build context.
|
|
180
|
+
|
|
181
|
+
`persist` paths must be absolute; `space run` bind-mounts each one from
|
|
182
|
+
`<space>/.state<path>` on the host (created on first run) so a container's mutable state
|
|
183
|
+
survives across runs. Both are validated at pack time.
|
|
184
|
+
|
|
185
|
+
## Fish shell integration 🐟
|
|
186
|
+
|
|
187
|
+
Shells can't let a child process change *their* working directory, so `space`
|
|
188
|
+
ships a small fish wrapper function plus completions (commands, subcommands,
|
|
189
|
+
spaces, statuses, config keys, repo refs). Install into fish's autoloaded
|
|
190
|
+
directories:
|
|
191
|
+
|
|
192
|
+
```fish
|
|
193
|
+
space shell fish install
|
|
194
|
+
exec fish
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
After restarting fish (or `exec fish`), `space new "…"` and
|
|
198
|
+
`space use <id>` will `cd` into the selected space once the command succeeds;
|
|
199
|
+
every other command keeps normal CLI behavior. 🚪 The functions and completions
|
|
200
|
+
are written under `~/.config/fish/`, so there's no need to edit `config.fish`.
|
|
201
|
+
For one-off testing without installing:
|
|
202
|
+
|
|
203
|
+
```fish
|
|
204
|
+
space shell init fish | source
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Configuration ⚙️
|
|
208
|
+
|
|
209
|
+
Config lives at `~/.config/space-cadet/config.yml` (XDG-aware) and defaults to:
|
|
210
|
+
|
|
211
|
+
```yaml
|
|
212
|
+
version: 1
|
|
213
|
+
base_dir: ~/architect # spaces_dir + src_dir hang off this by default
|
|
214
|
+
default_provider: github.com
|
|
215
|
+
default_organization:
|
|
216
|
+
git_clone_protocol: ssh # ssh | https
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Derived defaults: `spaces_dir` → `<base_dir>/spaces`, `src_dir` (evergreen
|
|
220
|
+
checkout root) → `<base_dir>/src`. Override either explicitly. View values with
|
|
221
|
+
`space config show`; set one with `space config set KEY VALUE`. Editable keys:
|
|
222
|
+
`base_dir`, `spaces_dir`, `src_dir`, `default_provider`, `default_organization`,
|
|
223
|
+
`git_clone_protocol`.
|
|
224
|
+
|
|
225
|
+
## Repos: evergreen, copy-on-write, concurrent ⚡
|
|
226
|
+
|
|
227
|
+
Repos are added to the current space under `repos/` and tracked in `space.yaml`.
|
|
228
|
+
When an up-to-date evergreen checkout exists at
|
|
229
|
+
`<src_dir>/<host>/<owner>/<name>` (e.g.
|
|
230
|
+
`~/architect/src/github.com/example-org/example-app` — tended by
|
|
231
|
+
[jetpks/repo-tender](https://github.com/jetpks/repo-tender)), `space` copies it
|
|
232
|
+
into the space instead of cloning over the network — a copy-on-write clone on
|
|
233
|
+
APFS. ⚡ Set `src_dir` empty to always clone:
|
|
234
|
+
|
|
235
|
+
```sh
|
|
236
|
+
space config set src_dir ""
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Clone URLs default to SSH (`git@github.com:example-org/example-app.git`); switch
|
|
240
|
+
with `space config set git_clone_protocol https`. Multiple repos passed to
|
|
241
|
+
`space repo add` are fetched **concurrently**, up to five at a time, on fibers —
|
|
242
|
+
no threads, all cooperative. 🧵 After each repo lands, `space` runs `mise trust`
|
|
243
|
+
in it. Each space also gets a workspace-local `tmp/` — use it instead of `/tmp`.
|
|
244
|
+
|
|
245
|
+
## Embedding 📚
|
|
246
|
+
|
|
247
|
+
```ruby
|
|
248
|
+
require "space_core" # config, state, XDG, terminal, git/mise clients,
|
|
249
|
+
# the space store — the `space` CLI runs on this alone
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Documentation 📖
|
|
253
|
+
|
|
254
|
+
- **[Command Reference](docs/reference.md)** — every command, flag, and behavior
|
|
255
|
+
- **[Releasing](docs/RELEASING.md)** — how a release lands
|
|
256
|
+
- **[Changelog](CHANGELOG.md)** — release history
|
|
257
|
+
|
|
258
|
+
## Development 🛠️
|
|
259
|
+
|
|
260
|
+
```sh
|
|
261
|
+
bundle install
|
|
262
|
+
bundle exec rake test # the minitest suite
|
|
263
|
+
bundle exec rake build # build the gem into pkg/
|
|
264
|
+
bundle exec rake install # build + install into your user gem home
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Contributing 💝
|
|
268
|
+
|
|
269
|
+
Bug reports and pull requests are welcome on GitHub at
|
|
270
|
+
[https://github.com/jetpks/space-cadet](https://github.com/jetpks/space-cadet)!
|
|
271
|
+
|
|
272
|
+
## License 📄
|
|
273
|
+
|
|
274
|
+
Available as open source under the terms of the
|
|
275
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
Made with 💖 and fibers 🧵 by Eric
|
data/exe/space
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
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)
|
|
@@ -0,0 +1,21 @@
|
|
|
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
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../oci_packer"
|
|
4
|
+
require_relative "../oci_builder"
|
|
5
|
+
|
|
6
|
+
module Space::Core::CLI
|
|
7
|
+
class Build < BaseCommand
|
|
8
|
+
desc "Build (and tag) the OCI image for the current space"
|
|
9
|
+
|
|
10
|
+
def call(**opts)
|
|
11
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
12
|
+
handle_errors do
|
|
13
|
+
result = store.current.bind do |space|
|
|
14
|
+
out_dir = space.path.join("build", "oci")
|
|
15
|
+
Space::Core::OciPacker.new(space: space, output_dir: out_dir).generate.bind do
|
|
16
|
+
Space::Core::OciBuilder.new(space: space, output_dir: out_dir).command
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
render(result) do |argv|
|
|
20
|
+
terminal.say "Building: #{argv.join(' ')}"
|
|
21
|
+
out.flush
|
|
22
|
+
Kernel.exec(*argv)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Space::Core::CLI
|
|
4
|
+
module Config
|
|
5
|
+
class Show < BaseCommand
|
|
6
|
+
desc "Show current config"
|
|
7
|
+
|
|
8
|
+
def call(**opts)
|
|
9
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
10
|
+
handle_errors do
|
|
11
|
+
rows = Space::Core::Config::EDITABLE_KEYS.map do |key|
|
|
12
|
+
value = project_config.data[key]
|
|
13
|
+
[key, value.nil? ? "" : value.to_s]
|
|
14
|
+
end
|
|
15
|
+
terminal.say terminal.table(%w[Key Value], rows)
|
|
16
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class ConfigPath < BaseCommand
|
|
22
|
+
desc "Print the config file path"
|
|
23
|
+
|
|
24
|
+
def call(**opts)
|
|
25
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
26
|
+
handle_errors do
|
|
27
|
+
terminal.say terminal.path(project_config.path)
|
|
28
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class Set < BaseCommand
|
|
34
|
+
desc "Set a config key"
|
|
35
|
+
argument :key, required: true, desc: "Config key"
|
|
36
|
+
argument :value, required: true, desc: "Config value"
|
|
37
|
+
|
|
38
|
+
def call(key:, value:, **opts)
|
|
39
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
40
|
+
handle_errors do
|
|
41
|
+
project_config.set(key, value)
|
|
42
|
+
stored = project_config.data[key]
|
|
43
|
+
terminal.success "Set #{key}=#{stored.nil? ? '' : stored.to_s}"
|
|
44
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Space::Core::CLI
|
|
4
|
+
class Current < BaseCommand
|
|
5
|
+
desc "Show the current space"
|
|
6
|
+
|
|
7
|
+
def call(**opts)
|
|
8
|
+
setup_terminal(**opts.slice(:color, :colors))
|
|
9
|
+
render(store.find) do |space|
|
|
10
|
+
terminal.say space.id.to_s
|
|
11
|
+
terminal.say terminal.path(space.path)
|
|
12
|
+
CLI.record_outcome(Outcome.new(exit_code: 0))
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|