boxdown 1.2.1 → 1.3.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.
- package/README.md +10 -0
- package/assets/devcontainer/README.md +12 -1
- package/assets/devcontainer/devcontainer.json +1 -1
- package/assets/devcontainer/hooks/post-create.sh +12 -1
- package/dist/bin/cli.cjs +1 -1
- package/dist/bin/cli.mjs +1 -1
- package/dist/{main-BDgyf2t5.cjs → main-CT2n9qcb.cjs} +448 -67
- package/dist/{main-J4_2Up3o.mjs → main-O__JaiXe.mjs} +431 -68
- package/dist/main-O__JaiXe.mjs.map +1 -0
- package/dist/main.cjs +4 -1
- package/dist/main.d.cts +92 -26
- package/dist/main.d.cts.map +1 -1
- package/dist/main.d.mts +92 -26
- package/dist/main.d.mts.map +1 -1
- package/dist/main.mjs +2 -2
- package/docs/features/lifecycle.md +13 -0
- package/docs/features/setup.md +5 -0
- package/docs/features/start-and-shell.md +5 -0
- package/docs/superpowers/plans/2026-07-18-architecture-aware-1password-installer.md +163 -0
- package/docs/superpowers/plans/2026-07-18-devcontainer-node-image-digest.md +341 -0
- package/docs/superpowers/plans/2026-07-19-container-runtime-readiness.md +1536 -0
- package/docs/superpowers/specs/2026-07-18-architecture-aware-1password-installer-design.md +63 -0
- package/docs/superpowers/specs/2026-07-18-devcontainer-node-image-digest-design.md +108 -0
- package/docs/superpowers/specs/2026-07-19-container-runtime-readiness-design.md +353 -0
- package/package.json +1 -1
- package/src/container-runtime.ts +295 -0
- package/src/devcontainer.ts +20 -4
- package/src/doctor.ts +48 -22
- package/src/main.ts +95 -11
- package/src/process.ts +50 -10
- package/src/progress.ts +63 -8
- package/dist/main-J4_2Up3o.mjs.map +0 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Architecture-Aware 1Password Installer Design
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Install the pinned 1Password CLI archive that matches the devcontainer's Linux
|
|
6
|
+
architecture, and add fast CI coverage for both supported architecture paths.
|
|
7
|
+
|
|
8
|
+
## Current Problem
|
|
9
|
+
|
|
10
|
+
`assets/devcontainer/hooks/post-create.sh` always downloads the 1Password
|
|
11
|
+
`op_linux_arm64` archive. On amd64 devcontainers this installs an incompatible
|
|
12
|
+
binary. The existing CI job runs on amd64, but its tests never execute the
|
|
13
|
+
installer's architecture selection, so the mismatch is not detected.
|
|
14
|
+
|
|
15
|
+
## Design
|
|
16
|
+
|
|
17
|
+
Keep the existing pinned 1Password CLI version and prebuilt zip installation
|
|
18
|
+
flow. Inside `install_1password_cli`, map the value from `uname -m` to the
|
|
19
|
+
1Password archive architecture:
|
|
20
|
+
|
|
21
|
+
- `x86_64` and `amd64` select `amd64`.
|
|
22
|
+
- `aarch64` and `arm64` select `arm64`.
|
|
23
|
+
- Any other value prints a warning and returns successfully without downloading
|
|
24
|
+
or installing a binary.
|
|
25
|
+
|
|
26
|
+
The selected architecture becomes part of the existing archive URL. No source
|
|
27
|
+
build, Buildx configuration, QEMU emulation, version change, or installer
|
|
28
|
+
refactor is required.
|
|
29
|
+
|
|
30
|
+
## Test Coverage
|
|
31
|
+
|
|
32
|
+
Add behavioral smoke tests that source the real post-create hook and invoke
|
|
33
|
+
`install_1password_cli` with controlled command shims. The shims replace
|
|
34
|
+
network and privileged filesystem operations while recording the requested
|
|
35
|
+
download URL.
|
|
36
|
+
|
|
37
|
+
The tests cover:
|
|
38
|
+
|
|
39
|
+
- `x86_64` selecting the `op_linux_amd64` archive.
|
|
40
|
+
- `aarch64` selecting the `op_linux_arm64` archive.
|
|
41
|
+
- An unsupported architecture returning successfully, warning, and performing
|
|
42
|
+
no download.
|
|
43
|
+
|
|
44
|
+
These tests run in the existing `pnpm run test` CI step on `ubuntu-latest`.
|
|
45
|
+
This gives the amd64 CI runner explicit coverage of both supported selection
|
|
46
|
+
branches without downloading 1Password or building a multi-architecture
|
|
47
|
+
container.
|
|
48
|
+
|
|
49
|
+
## Scope
|
|
50
|
+
|
|
51
|
+
- Modify `assets/devcontainer/hooks/post-create.sh` only for 1Password archive
|
|
52
|
+
selection and unsupported-architecture handling.
|
|
53
|
+
- Add focused tests to `__tests__/app.test.ts` using the repository's existing
|
|
54
|
+
shell-script test conventions.
|
|
55
|
+
- Do not alter the Snyk installer, devcontainer image, CI runner matrix, or
|
|
56
|
+
other lifecycle behavior.
|
|
57
|
+
|
|
58
|
+
## Verification
|
|
59
|
+
|
|
60
|
+
Use test-driven development: add the focused architecture tests and confirm
|
|
61
|
+
they fail against the hard-coded arm64 URL, implement the minimum shell change,
|
|
62
|
+
then rerun the focused tests. Finish with the repository's full test, lint,
|
|
63
|
+
build, shell syntax, and diff checks.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Devcontainer Node Image Digest Pinning
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Make Boxdown's packaged devcontainer base image reproducible across rebuilds
|
|
6
|
+
and host architectures while preserving the existing Node 24, Debian trixie,
|
|
7
|
+
and slim-image track. Keep the immutable image reference current through
|
|
8
|
+
reviewable automated pull requests.
|
|
9
|
+
|
|
10
|
+
## Scope
|
|
11
|
+
|
|
12
|
+
This change applies to the reusable devcontainer template at
|
|
13
|
+
`assets/devcontainer/devcontainer.json`. It does not change Boxdown's runtime
|
|
14
|
+
generation model, the Dev Container Feature pins, npm dependency automation,
|
|
15
|
+
or GitHub Actions dependency automation.
|
|
16
|
+
|
|
17
|
+
## Image Reference
|
|
18
|
+
|
|
19
|
+
The template will replace the mutable reference:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
node:24-trixie-slim
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
with the same tag plus `@sha256:` and the verified 64-hex-character
|
|
26
|
+
multi-platform index digest.
|
|
27
|
+
|
|
28
|
+
The implementation will resolve the current digest from the upstream Node
|
|
29
|
+
image registry and verify that it identifies the multi-platform image index,
|
|
30
|
+
not an architecture-specific child manifest. Keeping the tag documents the
|
|
31
|
+
intended Node 24 and Debian trixie slim update track. The digest makes the
|
|
32
|
+
actual selected index immutable, so AMD64 and ARM64 hosts resolve their
|
|
33
|
+
platform image from the same pinned release set.
|
|
34
|
+
|
|
35
|
+
The tag deliberately remains at Node major-version precision. Node patch
|
|
36
|
+
releases and upstream rebuilds stay explicit through digest-update pull
|
|
37
|
+
requests without moving Boxdown to another Node major or Debian variant.
|
|
38
|
+
|
|
39
|
+
## Update Automation
|
|
40
|
+
|
|
41
|
+
A root `renovate.json` will configure Renovate's native devcontainer manager.
|
|
42
|
+
The configuration will:
|
|
43
|
+
|
|
44
|
+
- enable only the devcontainer manager, avoiding overlap with the existing
|
|
45
|
+
Dependabot npm and GitHub Actions configuration;
|
|
46
|
+
- extend devcontainer file matching to
|
|
47
|
+
`assets/devcontainer/devcontainer.json`, which is outside Renovate's default
|
|
48
|
+
root `.devcontainer` locations;
|
|
49
|
+
- disable Dev Container Feature updates so the existing digest-pinned Feature
|
|
50
|
+
set remains outside this change;
|
|
51
|
+
- match only the `node` image dependency in the packaged template;
|
|
52
|
+
- preserve the `24-trixie-slim` tag and update its digest; and
|
|
53
|
+
- allow digest-refresh pull requests on a monthly schedule.
|
|
54
|
+
|
|
55
|
+
The Renovate GitHub app performs the registry lookup and opens the pull
|
|
56
|
+
request. Boxdown does not add a repository-owned scheduled workflow or a
|
|
57
|
+
repository token. Enabling the app for the repository is an operational
|
|
58
|
+
prerequisite outside the committed code.
|
|
59
|
+
|
|
60
|
+
## Documentation
|
|
61
|
+
|
|
62
|
+
The packaged devcontainer README will describe the tag-plus-index-digest
|
|
63
|
+
reference, its cross-platform reproducibility property, and Renovate's role in
|
|
64
|
+
refreshing it through auditable pull requests. Existing documentation about
|
|
65
|
+
the Node 24 trixie slim base and digest-pinned Features remains accurate.
|
|
66
|
+
|
|
67
|
+
## Test Strategy
|
|
68
|
+
|
|
69
|
+
A focused repository test will read the packaged devcontainer source and
|
|
70
|
+
assert that:
|
|
71
|
+
|
|
72
|
+
- its base image is exactly the intended `node:24-trixie-slim` tag followed by
|
|
73
|
+
a 64-hex-character SHA-256 digest;
|
|
74
|
+
- the Renovate configuration enables only the devcontainer manager;
|
|
75
|
+
- the additional manager file pattern covers the packaged template;
|
|
76
|
+
- Feature dependencies are disabled; and
|
|
77
|
+
- the Node image rule enables digest pinning on the monthly schedule.
|
|
78
|
+
|
|
79
|
+
The test will be added before the production configuration changes and must be
|
|
80
|
+
observed failing for the missing digest and Renovate configuration. After the
|
|
81
|
+
change, verification will run the focused test, full test suite, lint, build,
|
|
82
|
+
JSON and JSON-with-comments parsing, registry inspection of the pinned index,
|
|
83
|
+
and `git diff --check`.
|
|
84
|
+
|
|
85
|
+
## Alternatives Considered
|
|
86
|
+
|
|
87
|
+
### Dependabot through a Dockerfile
|
|
88
|
+
|
|
89
|
+
Moving the base reference into a Dockerfile would let Dependabot's Docker
|
|
90
|
+
ecosystem update it, but it would change the devcontainer architecture solely
|
|
91
|
+
to accommodate the updater. GitHub's `devcontainers` ecosystem updates
|
|
92
|
+
Features rather than the `image` field, so it cannot directly maintain the
|
|
93
|
+
current template.
|
|
94
|
+
|
|
95
|
+
### Repository-owned scheduled workflow
|
|
96
|
+
|
|
97
|
+
A custom workflow could resolve the tag, edit the digest, and open pull
|
|
98
|
+
requests. It would duplicate registry, scheduling, authentication, and pull
|
|
99
|
+
request behavior already provided by Renovate and would add workflow and token
|
|
100
|
+
maintenance.
|
|
101
|
+
|
|
102
|
+
## Decision Record
|
|
103
|
+
|
|
104
|
+
Use Renovate's native devcontainer support and retain the human-readable
|
|
105
|
+
`node:24-trixie-slim` tag. Pin the verified multi-platform index digest and
|
|
106
|
+
scope automation to only that image in the packaged template. This yields
|
|
107
|
+
immutable rebuild inputs without broadening Boxdown's dependency automation
|
|
108
|
+
or changing its generated-devcontainer architecture.
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# Container Runtime Readiness and Lifecycle Preflight
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Make every Boxdown command that can create or start a devcontainer recover
|
|
6
|
+
cleanly when Docker has just been launched, while preserving `boxdown start` as
|
|
7
|
+
a standalone command after a missing or failed `boxdown setup`.
|
|
8
|
+
|
|
9
|
+
## Problem
|
|
10
|
+
|
|
11
|
+
`boxdown setup` currently runs required host-readiness checks before prompts,
|
|
12
|
+
workspace state, or Docker work. Other commands that can create a container do
|
|
13
|
+
not share that gate. A user can therefore run setup while Docker is stopped,
|
|
14
|
+
start Docker, and then run `boxdown start` while Docker Desktop or its selected
|
|
15
|
+
Buildx builder is still initializing. The Dev Containers CLI proceeds far
|
|
16
|
+
enough to invoke `docker buildx build`, then returns a generic JSON error
|
|
17
|
+
envelope that does not explain the lifecycle gap.
|
|
18
|
+
|
|
19
|
+
The existing checks also establish only that the Docker CLI exists and that the
|
|
20
|
+
daemon answers `docker info`. They do not distinguish these Buildx states:
|
|
21
|
+
|
|
22
|
+
- Buildx is unavailable and the Dev Containers CLI will use its supported
|
|
23
|
+
classic-build fallback.
|
|
24
|
+
- Buildx is discoverable but its selected builder is not operational yet.
|
|
25
|
+
- Buildx is operational and ready for a Feature image build.
|
|
26
|
+
|
|
27
|
+
## Decisions
|
|
28
|
+
|
|
29
|
+
- `boxdown start` remains valid without a successful prior setup.
|
|
30
|
+
- Start does not install setup-only SSH aliases or external app integrations.
|
|
31
|
+
- Commands that may create or start a container share one readiness gate.
|
|
32
|
+
- Transient Docker daemon and Buildx builder failures are polled once per second
|
|
33
|
+
for at most 60 seconds.
|
|
34
|
+
- A missing Docker executable is terminal and fails immediately.
|
|
35
|
+
- Missing Buildx is non-blocking because the bundled Dev Containers CLI already
|
|
36
|
+
supports a non-Buildx build path.
|
|
37
|
+
- Discoverable but unusable Buildx is transient until the readiness deadline,
|
|
38
|
+
then terminal with the last builder diagnostic.
|
|
39
|
+
- `devcontainer up` is invoked once after readiness succeeds. Boxdown does not
|
|
40
|
+
retry genuine image, Feature, Dockerfile, registry, or lifecycle failures.
|
|
41
|
+
- Workspace metadata remains inventory for a workspace Boxdown has touched; it
|
|
42
|
+
does not become a setup-completion record.
|
|
43
|
+
- No `setupCompleted` field or migration is introduced.
|
|
44
|
+
|
|
45
|
+
## Alternatives Considered
|
|
46
|
+
|
|
47
|
+
### Shared CLI lifecycle gate
|
|
48
|
+
|
|
49
|
+
This is the selected design. A focused container-runtime module owns probing
|
|
50
|
+
and bounded waiting. CLI lifecycle orchestration calls it before metadata or
|
|
51
|
+
container work, and `doctor` reuses the same single-attempt probe semantics.
|
|
52
|
+
|
|
53
|
+
This keeps host-runtime policy out of devcontainer configuration code, makes
|
|
54
|
+
the command scope explicit, and preserves setup's stronger ordering.
|
|
55
|
+
|
|
56
|
+
### Readiness inside `startDevcontainer`
|
|
57
|
+
|
|
58
|
+
Putting the gate in `startDevcontainer` would make it difficult for a caller to
|
|
59
|
+
forget the check. It would, however, run after setup has already entered its
|
|
60
|
+
workflow unless setup retained a second preflight. It would also couple Docker
|
|
61
|
+
host diagnostics and waiting policy to the lower-level devcontainer lifecycle
|
|
62
|
+
implementation.
|
|
63
|
+
|
|
64
|
+
### Retry `devcontainer up`
|
|
65
|
+
|
|
66
|
+
Retrying the failed Dev Containers command is too late and cannot reliably
|
|
67
|
+
distinguish runtime initialization from a real build failure. It could repeat
|
|
68
|
+
expensive work or obscure an actionable Feature, registry, or Dockerfile error.
|
|
69
|
+
|
|
70
|
+
## Architecture
|
|
71
|
+
|
|
72
|
+
### Container runtime module
|
|
73
|
+
|
|
74
|
+
Add `src/container-runtime.ts` as the single owner of Docker and Buildx
|
|
75
|
+
readiness semantics. It exposes two levels of behavior:
|
|
76
|
+
|
|
77
|
+
- A single-attempt probe used by `doctor` and by each waiter iteration.
|
|
78
|
+
- A bounded waiter used before container-creating lifecycle commands.
|
|
79
|
+
|
|
80
|
+
The module accepts an injected command runner, clock, and sleep function so its
|
|
81
|
+
tests do not use the real Docker daemon or wall-clock delays.
|
|
82
|
+
|
|
83
|
+
The probe returns a structured result rather than throwing. Its stable states
|
|
84
|
+
are:
|
|
85
|
+
|
|
86
|
+
- `ready`: Docker is reachable and Buildx is either operational or unavailable
|
|
87
|
+
with a supported fallback.
|
|
88
|
+
- `waiting`: Docker or a discoverable Buildx builder may still become ready.
|
|
89
|
+
- `failed`: a terminal prerequisite is missing.
|
|
90
|
+
|
|
91
|
+
The structured result includes:
|
|
92
|
+
|
|
93
|
+
- the high-level reason;
|
|
94
|
+
- whether the Dev Containers CLI will use Buildx or its fallback;
|
|
95
|
+
- the command whose last attempt failed;
|
|
96
|
+
- compact stdout/stderr detail suitable for an actionable error; and
|
|
97
|
+
- non-blocking warnings.
|
|
98
|
+
|
|
99
|
+
The stable terminal and transient reasons are:
|
|
100
|
+
|
|
101
|
+
- `docker-cli-unavailable`: terminal;
|
|
102
|
+
- `docker-daemon-unavailable`: transient until timeout;
|
|
103
|
+
- `buildx-builder-unavailable`: transient until timeout.
|
|
104
|
+
|
|
105
|
+
### Readiness commands
|
|
106
|
+
|
|
107
|
+
Each probe performs only the commands required by the state reached:
|
|
108
|
+
|
|
109
|
+
1. Run `docker --version`. A spawn failure or any nonzero exit produces the
|
|
110
|
+
terminal `docker-cli-unavailable` result.
|
|
111
|
+
2. Run `docker info`. A nonzero result produces the transient
|
|
112
|
+
`docker-daemon-unavailable` result.
|
|
113
|
+
3. Run `docker buildx version`. A nonzero result produces a ready result with a
|
|
114
|
+
fallback warning; it does not block container startup.
|
|
115
|
+
4. Run `docker buildx inspect --bootstrap`. A nonzero result produces the
|
|
116
|
+
transient `buildx-builder-unavailable` result. Success produces Buildx-ready
|
|
117
|
+
status.
|
|
118
|
+
|
|
119
|
+
`--bootstrap` is intentional: the selected builder is the builder the Dev
|
|
120
|
+
Containers CLI will use, and readiness must establish that it can start before
|
|
121
|
+
Boxdown begins the Feature build. The command may initialize a selected custom
|
|
122
|
+
builder, but Boxdown does not create, replace, select, or delete builders.
|
|
123
|
+
|
|
124
|
+
### Bounded waiter
|
|
125
|
+
|
|
126
|
+
The waiter uses these defaults:
|
|
127
|
+
|
|
128
|
+
- timeout: 60,000 milliseconds;
|
|
129
|
+
- poll interval: 1,000 milliseconds;
|
|
130
|
+
- first probe: immediate;
|
|
131
|
+
- deadline behavior: retain and report the final failed probe;
|
|
132
|
+
- terminal failure behavior: return immediately without sleeping.
|
|
133
|
+
|
|
134
|
+
The waiter never launches Docker Desktop or modifies Docker contexts. It gives
|
|
135
|
+
a daemon or builder that the user has already launched time to become ready.
|
|
136
|
+
|
|
137
|
+
## Command Scope and Data Flow
|
|
138
|
+
|
|
139
|
+
The readiness gate applies to commands that may create or start a container:
|
|
140
|
+
|
|
141
|
+
| Command path | Waits for readiness | May create/start |
|
|
142
|
+
| --- | --- | --- |
|
|
143
|
+
| `setup` | Yes | Yes |
|
|
144
|
+
| `start` / `shell` | Yes | Yes |
|
|
145
|
+
| `ssh-proxy` | Yes | Yes |
|
|
146
|
+
| `tunnel` | Yes | Yes |
|
|
147
|
+
| `refresh-gh-token` | Yes | Yes |
|
|
148
|
+
| `codex`, `claude`, `opencode`, `antigravity` | Yes | Yes |
|
|
149
|
+
| `refresh-gh-token-running` | No | No |
|
|
150
|
+
| `ssh install`, `ssh uninstall` | No | No |
|
|
151
|
+
| `doctor`, `status`, `list` | No wait | No |
|
|
152
|
+
| `stop`, `down`, `purge` | No bring-up wait | No |
|
|
153
|
+
|
|
154
|
+
`doctor` performs one readiness snapshot and reports it; it does not poll for
|
|
155
|
+
60 seconds.
|
|
156
|
+
|
|
157
|
+
For non-setup container lifecycle commands, the sequence is:
|
|
158
|
+
|
|
159
|
+
1. Resolve the workspace and alias.
|
|
160
|
+
2. Create the managed command logger so readiness details can be preserved.
|
|
161
|
+
3. Wait for container-runtime readiness.
|
|
162
|
+
4. Write workspace inventory metadata.
|
|
163
|
+
5. Generate runtime configuration and invoke the requested lifecycle.
|
|
164
|
+
|
|
165
|
+
A readiness failure may leave a diagnostic command log, but it does not create
|
|
166
|
+
workspace metadata, generated devcontainer configuration, an SSH identity, or a
|
|
167
|
+
container.
|
|
168
|
+
|
|
169
|
+
Setup retains stronger state-free ordering:
|
|
170
|
+
|
|
171
|
+
1. Wait for container-runtime readiness without creating a workspace logger.
|
|
172
|
+
2. Run the remaining required doctor checks.
|
|
173
|
+
3. Show optional-target prompts.
|
|
174
|
+
4. Write inventory metadata.
|
|
175
|
+
5. Start the container and install the SSH alias and selected integrations.
|
|
176
|
+
|
|
177
|
+
This preserves the existing contract that setup preflight failures do not
|
|
178
|
+
create workspace data. Setup reports its final readiness diagnostic directly
|
|
179
|
+
because no managed log exists yet.
|
|
180
|
+
|
|
181
|
+
## User Experience
|
|
182
|
+
|
|
183
|
+
Interactive mode adds one stable checklist step labelled `Checking container
|
|
184
|
+
runtime`. When a transient condition is observed, the detail changes to either
|
|
185
|
+
`Waiting for Docker daemon` or `Waiting for Docker Buildx builder`. Individual
|
|
186
|
+
poll attempts do not add terminal lines or restart the spinner.
|
|
187
|
+
|
|
188
|
+
Verbose mode prints the first transient observation, state transitions, and
|
|
189
|
+
final outcome. It does not print identical output once per second.
|
|
190
|
+
|
|
191
|
+
When Buildx is unavailable, Boxdown emits one warning that the Dev Containers
|
|
192
|
+
CLI will use its fallback. It then proceeds without a delay.
|
|
193
|
+
|
|
194
|
+
Timeout errors include:
|
|
195
|
+
|
|
196
|
+
- the failed capability;
|
|
197
|
+
- the 60-second timeout;
|
|
198
|
+
- the last compact command diagnostic;
|
|
199
|
+
- an appropriate manual check, `docker info` or `docker buildx inspect`; and
|
|
200
|
+
- the workspace command-log path when the command has an active logger.
|
|
201
|
+
|
|
202
|
+
Examples of error summaries are:
|
|
203
|
+
|
|
204
|
+
```text
|
|
205
|
+
Docker daemon did not become ready within 60 seconds.
|
|
206
|
+
Last check: docker info
|
|
207
|
+
Detail: Cannot connect to the Docker daemon ...
|
|
208
|
+
Check Docker with: docker info
|
|
209
|
+
Command log: /path/to/boxdown.log
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
```text
|
|
213
|
+
Docker Buildx builder did not become ready within 60 seconds.
|
|
214
|
+
Last check: docker buildx inspect --bootstrap
|
|
215
|
+
Detail: failed to initialize builder ...
|
|
216
|
+
Check Buildx with: docker buildx inspect
|
|
217
|
+
Command log: /path/to/boxdown.log
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Dev Containers Failure Reporting
|
|
221
|
+
|
|
222
|
+
Readiness success marks the boundary between runtime initialization and the
|
|
223
|
+
actual Dev Containers lifecycle. Any subsequent `devcontainer up` failure is
|
|
224
|
+
reported without an automatic retry.
|
|
225
|
+
|
|
226
|
+
The concise failure formatter will:
|
|
227
|
+
|
|
228
|
+
- handle a zero line budget as zero lines instead of using `.slice(-0)`;
|
|
229
|
+
- preserve stderr before allocating remaining space to stdout;
|
|
230
|
+
- recognize a Dev Containers JSON object with `outcome: "error"` as a wrapper;
|
|
231
|
+
- avoid presenting the wrapper's repeated build command as the root cause when
|
|
232
|
+
more specific stderr exists;
|
|
233
|
+
- state explicitly when the wrapper contains no nested Docker diagnostic;
|
|
234
|
+
- include the managed command-log path when available; and
|
|
235
|
+
- retain the `--verbose` recovery instruction.
|
|
236
|
+
|
|
237
|
+
The full redacted stdout and stderr streams continue to be stored by the
|
|
238
|
+
existing workspace command logger. The readiness work does not weaken current
|
|
239
|
+
secret redaction.
|
|
240
|
+
|
|
241
|
+
## Workspace State Semantics
|
|
242
|
+
|
|
243
|
+
`boxdown start` is a recovery-capable standalone command. It may create the
|
|
244
|
+
Boxdown SSH identity and generated devcontainer config required for container
|
|
245
|
+
operation, but it does not install an SSH host alias or modify Codex or Claude
|
|
246
|
+
application configuration.
|
|
247
|
+
|
|
248
|
+
Workspace metadata continues to mean that Boxdown reached a ready runtime and
|
|
249
|
+
attempted a lifecycle for that workspace. A build failure after readiness may
|
|
250
|
+
therefore leave metadata and a diagnostic log. A readiness failure leaves no
|
|
251
|
+
metadata. This distinction does not require a metadata schema change.
|
|
252
|
+
|
|
253
|
+
## Testing Strategy
|
|
254
|
+
|
|
255
|
+
### Container-runtime unit tests
|
|
256
|
+
|
|
257
|
+
Use an injected command runner to verify:
|
|
258
|
+
|
|
259
|
+
- missing Docker exits immediately with `docker-cli-unavailable`;
|
|
260
|
+
- an unavailable daemon returns `docker-daemon-unavailable` without probing
|
|
261
|
+
Buildx;
|
|
262
|
+
- missing Buildx returns ready fallback status and one warning;
|
|
263
|
+
- successful Buildx version plus failed bootstrap returns
|
|
264
|
+
`buildx-builder-unavailable`;
|
|
265
|
+
- successful Docker, Buildx version, and bootstrap returns Buildx-ready status;
|
|
266
|
+
- command output is compacted and retained in failure details.
|
|
267
|
+
|
|
268
|
+
Use injected clock and sleep functions to verify:
|
|
269
|
+
|
|
270
|
+
- the first probe happens without sleeping;
|
|
271
|
+
- two transient failures followed by success produce exactly two sleeps;
|
|
272
|
+
- terminal failures never sleep;
|
|
273
|
+
- polling stops at the 60-second deadline;
|
|
274
|
+
- the timeout reports the last probe rather than the first; and
|
|
275
|
+
- identical transient output does not create repeated user-facing messages.
|
|
276
|
+
|
|
277
|
+
### CLI lifecycle tests
|
|
278
|
+
|
|
279
|
+
Extend the existing CLI execution tests to verify:
|
|
280
|
+
|
|
281
|
+
- `start` after a failed setup can proceed when runtime readiness becomes
|
|
282
|
+
healthy;
|
|
283
|
+
- readiness runs before metadata for each container-creating command path;
|
|
284
|
+
- readiness failure creates no metadata, generated config, SSH key, or
|
|
285
|
+
container call;
|
|
286
|
+
- setup still performs readiness before prompts or state writes;
|
|
287
|
+
- `refresh-gh-token-running` and SSH-only commands do not wait;
|
|
288
|
+
- every coding-agent command shares the same gate; and
|
|
289
|
+
- a post-readiness `devcontainer up` failure is invoked once and not retried.
|
|
290
|
+
|
|
291
|
+
Command-scope coverage will use a table-driven test so adding a new
|
|
292
|
+
container-creating CLI command requires an explicit readiness decision.
|
|
293
|
+
|
|
294
|
+
### Failure-formatting tests
|
|
295
|
+
|
|
296
|
+
Verify that:
|
|
297
|
+
|
|
298
|
+
- a zero stdout line budget produces no stdout lines;
|
|
299
|
+
- specific stderr is retained ahead of the generic JSON wrapper;
|
|
300
|
+
- a wrapper-only failure explains that the nested diagnostic was unavailable;
|
|
301
|
+
- logged lifecycle failures show the exact command-log path; and
|
|
302
|
+
- secret redaction remains unchanged.
|
|
303
|
+
|
|
304
|
+
### Complete verification
|
|
305
|
+
|
|
306
|
+
After the focused tests pass, run:
|
|
307
|
+
|
|
308
|
+
```sh
|
|
309
|
+
pnpm test
|
|
310
|
+
pnpm lint
|
|
311
|
+
pnpm build
|
|
312
|
+
git diff --check
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
No automated test requires a real Docker daemon, Docker Desktop, registry
|
|
316
|
+
network access, or wall-clock waiting.
|
|
317
|
+
|
|
318
|
+
## Documentation
|
|
319
|
+
|
|
320
|
+
Update the README and lifecycle documentation to state that:
|
|
321
|
+
|
|
322
|
+
- `start` works without a completed setup;
|
|
323
|
+
- setup-only SSH and application integrations remain exclusive to setup;
|
|
324
|
+
- container-creating commands wait up to 60 seconds for Docker and an available
|
|
325
|
+
Buildx builder;
|
|
326
|
+
- missing Buildx uses the Dev Containers CLI fallback; and
|
|
327
|
+
- timeout errors point to `docker info`, `docker buildx inspect`, and the
|
|
328
|
+
workspace command log.
|
|
329
|
+
|
|
330
|
+
## Non-Goals
|
|
331
|
+
|
|
332
|
+
- Launching or restarting Docker Desktop automatically.
|
|
333
|
+
- Creating, selecting, repairing, or deleting Buildx builders.
|
|
334
|
+
- Retrying `devcontainer up` or individual Docker builds.
|
|
335
|
+
- Classifying every possible Docker, registry, Feature, or Dockerfile error.
|
|
336
|
+
- Adding setup-completion state or migrating workspace metadata.
|
|
337
|
+
- Changing the packaged Node base image or Dev Container Feature pins.
|
|
338
|
+
- Installing setup-only SSH or external app integrations from `start`.
|
|
339
|
+
|
|
340
|
+
## Success Criteria
|
|
341
|
+
|
|
342
|
+
- A user can run `start` after a failed setup and recover once Docker becomes
|
|
343
|
+
ready, without rerunning setup.
|
|
344
|
+
- Docker and Buildx startup races receive a bounded wait rather than an opaque
|
|
345
|
+
immediate build failure.
|
|
346
|
+
- Every current container-creating command uses the shared readiness contract.
|
|
347
|
+
- Readiness failures do not create workspace metadata, generated config, an SSH
|
|
348
|
+
identity, or a container. Non-setup lifecycle commands may retain only their
|
|
349
|
+
diagnostic command log.
|
|
350
|
+
- Genuine post-readiness build failures execute once and retain their useful
|
|
351
|
+
diagnostic context.
|
|
352
|
+
- Setup preserves its state-free preflight ordering.
|
|
353
|
+
- Existing workspaces require no metadata migration.
|