boxdown 1.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.
Files changed (58) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +115 -0
  3. package/assets/devcontainer/README.md +177 -0
  4. package/assets/devcontainer/devcontainer.json +83 -0
  5. package/assets/devcontainer/hooks/initialize.sh +55 -0
  6. package/assets/devcontainer/hooks/post-create.sh +67 -0
  7. package/assets/devcontainer/hooks/post-start.sh +34 -0
  8. package/assets/devcontainer/ssh-config-install.sh +172 -0
  9. package/assets/devcontainer/start.sh +485 -0
  10. package/assets/devcontainer/utils/codex-cli-update.sh +9 -0
  11. package/assets/devcontainer/utils/coding-agent-cli-update.sh +360 -0
  12. package/assets/devcontainer/utils/deps-install.sh +87 -0
  13. package/assets/devcontainer/utils/ssh-bootstrap.sh +200 -0
  14. package/dist/bin/cli.cjs +12 -0
  15. package/dist/bin/cli.d.cts +1 -0
  16. package/dist/bin/cli.d.mts +1 -0
  17. package/dist/bin/cli.mjs +14 -0
  18. package/dist/bin/cli.mjs.map +1 -0
  19. package/dist/main-BuEptwlL.cjs +1707 -0
  20. package/dist/main-ZFTrSVgt.mjs +1685 -0
  21. package/dist/main-ZFTrSVgt.mjs.map +1 -0
  22. package/dist/main.cjs +7 -0
  23. package/dist/main.d.cts +24 -0
  24. package/dist/main.d.cts.map +1 -0
  25. package/dist/main.d.mts +24 -0
  26. package/dist/main.d.mts.map +1 -0
  27. package/dist/main.mjs +3 -0
  28. package/docs/README.md +34 -0
  29. package/docs/architecture.md +75 -0
  30. package/docs/conventions.md +29 -0
  31. package/docs/development.md +59 -0
  32. package/docs/features/README.md +14 -0
  33. package/docs/features/generated-config-and-state.md +64 -0
  34. package/docs/features/github-auth-refresh.md +64 -0
  35. package/docs/features/lifecycle.md +64 -0
  36. package/docs/features/ssh-config-and-proxy.md +60 -0
  37. package/docs/features/start-and-shell.md +83 -0
  38. package/docs/testing.md +63 -0
  39. package/docs/todo.md +170 -0
  40. package/package.json +128 -0
  41. package/src/bin/cli.ts +9 -0
  42. package/src/coding-agents.ts +22 -0
  43. package/src/config.ts +81 -0
  44. package/src/constants.ts +9 -0
  45. package/src/devcontainer-cli.ts +57 -0
  46. package/src/devcontainer.ts +394 -0
  47. package/src/doctor.ts +139 -0
  48. package/src/github-git-auth.ts +143 -0
  49. package/src/jsonc.ts +123 -0
  50. package/src/list.ts +102 -0
  51. package/src/main.ts +362 -0
  52. package/src/metadata.ts +84 -0
  53. package/src/paths.ts +117 -0
  54. package/src/process.ts +94 -0
  55. package/src/shell.ts +60 -0
  56. package/src/ssh-config.ts +113 -0
  57. package/src/ssh-key.ts +52 -0
  58. package/src/status.ts +327 -0
@@ -0,0 +1,64 @@
1
+ # GitHub Auth Refresh
2
+
3
+ ## Commands
4
+
5
+ ```sh
6
+ boxdown refresh-gh-token
7
+ boxdown refresh-gh-token-running
8
+ ```
9
+
10
+ Both commands copy host GitHub CLI auth into the container using the host token
11
+ from:
12
+
13
+ ```sh
14
+ gh auth token
15
+ ```
16
+
17
+ They do not start a browser login or device-code flow.
18
+
19
+ These commands are explicit on purpose. Normal `boxdown start`, coding-agent
20
+ launches, and SSH proxy connections do not copy GitHub credentials into the
21
+ container.
22
+
23
+ ## refresh-gh-token
24
+
25
+ `refresh-gh-token` starts or reuses the devcontainer, then refreshes GitHub CLI
26
+ auth inside it.
27
+
28
+ Use this when the container might not already be running.
29
+
30
+ ## refresh-gh-token-running
31
+
32
+ `refresh-gh-token-running` requires a running devcontainer for the workspace.
33
+ It fails early when no matching running container exists.
34
+
35
+ Use this when you want to refresh auth without accidentally starting a
36
+ container.
37
+
38
+ ## Container Work
39
+
40
+ When a host token is available, Boxdown runs inside the container:
41
+
42
+ ```sh
43
+ gh auth login --hostname github.com --git-protocol https --with-token --insecure-storage
44
+ ```
45
+
46
+ It also configures this repository's local Git config so GitHub remotes use the
47
+ container's authenticated `gh` for `git fetch`, `git pull`, and `git push`.
48
+ For GitHub remotes, Boxdown:
49
+
50
+ - rewrites fetch and push URLs to `https://github.com/<owner>/<repo>.git`
51
+ - resets inherited `credential.https://github.com.helper` entries locally
52
+ - adds `!gh auth git-credential` as the local GitHub credential helper
53
+ - adds a repository-specific HTTPS self-rewrite so broader host rewrites like
54
+ `url.git@github.com:.insteadOf=https://github.com/` do not force SSH inside
55
+ the container
56
+
57
+ The local Git config changes are written to the workspace repository because the
58
+ host checkout is mounted into the devcontainer.
59
+
60
+ If host `gh` is missing, logged out, or cannot return a token, the refresh is a
61
+ no-op.
62
+
63
+ `OP_SERVICE_ACCOUNT_TOKEN`, when present, is a 1Password service account token.
64
+ It is not a GitHub token and is not used by `gh` or GitHub Git operations.
@@ -0,0 +1,64 @@
1
+ # Lifecycle Commands
2
+
3
+ ## Commands
4
+
5
+ ```sh
6
+ boxdown list
7
+ boxdown list --json
8
+ boxdown status
9
+ boxdown status --json
10
+ boxdown stop
11
+ boxdown down
12
+ boxdown doctor
13
+ ```
14
+
15
+ Workspace-targeting commands accept `--workspace <path>`. `status` also accepts
16
+ `--alias <name>` so its output can match a custom SSH host alias.
17
+
18
+ ## List
19
+
20
+ `list` shows every workspace with Boxdown metadata under the data root,
21
+ regardless of the directory where the command is run. Human output includes
22
+ `STATE`, `REPO`, `PATH`, `SSH ALIAS`, and `CONTAINER` columns.
23
+
24
+ `list --json` prints the same inventory as structured JSON. Docker state is
25
+ best-effort: if Docker is unavailable, entries still print and their container
26
+ state is `unknown`. If a recorded repository path no longer exists, the entry is
27
+ shown as `missing`.
28
+
29
+ ## Status
30
+
31
+ `status` is read-only. It reports the resolved workspace, intended cache/data
32
+ paths, generated config path, SSH key paths, SSH alias, and the matching Docker
33
+ container state without recording the workspace in Boxdown metadata.
34
+
35
+ Human output distinguishes intended values from detected state. For example, an
36
+ SSH alias can be shown as a computed default even when the matching Boxdown SSH
37
+ config block has not been installed. Existing paths are labeled `exists`,
38
+ missing paths are labeled `missing`, and managed SSH config blocks are labeled
39
+ `installed`, `missing`, or `outdated`. Healthy values are color-coded green and
40
+ missing or unhealthy values are color-coded red.
41
+
42
+ `status --json` prints the same information as structured JSON for scripts.
43
+ `status` exits 0 only when the generated config exists, devcontainer assets
44
+ exist, SSH key material exists, the runtime public key exists, and the
45
+ workspace container is running. Missing setup or a stopped/absent container is
46
+ reported in the output and exits nonzero. Installing an SSH alias is optional
47
+ and is not required for a healthy status exit.
48
+
49
+ ## Stop and Down
50
+
51
+ `stop` stops the workspace devcontainer when it is running. If the container is
52
+ already stopped or absent, it prints a short message and exits 0.
53
+
54
+ `down` removes the workspace devcontainer with Docker. It does not remove
55
+ Boxdown cache, generated config, data directories, or SSH keys.
56
+
57
+ ## Doctor
58
+
59
+ `doctor` validates required host prerequisites: Node, Docker CLI, Docker
60
+ daemon access, SSH tools, packaged devcontainer assets, and Boxdown's packaged
61
+ `@devcontainers/cli` dependency.
62
+
63
+ GitHub CLI auth is optional. Missing or unauthenticated `gh` is reported as a
64
+ warning rather than a failure.
@@ -0,0 +1,60 @@
1
+ # SSH Config and Proxy Workflow
2
+
3
+ ## Commands
4
+
5
+ ```sh
6
+ boxdown ssh-config install
7
+ boxdown ssh-proxy
8
+ ```
9
+
10
+ `boxdown ssh-config` is accepted as a convenience shortcut for
11
+ `boxdown ssh-config install`, but docs use the explicit install form.
12
+
13
+ `ssh-proxy` is primarily an internal command launched by OpenSSH as a
14
+ `ProxyCommand`.
15
+
16
+ ## SSH Alias Installation
17
+
18
+ By default, Boxdown creates an alias named:
19
+
20
+ ```text
21
+ <repo-name>-devcontainer
22
+ ```
23
+
24
+ The generated SSH config block includes:
25
+
26
+ - `User node`
27
+ - a per-workspace host identity file
28
+ - `IdentitiesOnly yes`
29
+ - a `ProxyCommand` that runs the current Boxdown installation's built CLI
30
+
31
+ The block is wrapped in Boxdown markers so repeated installs replace the managed
32
+ block instead of duplicating it.
33
+
34
+ `boxdown status` reports whether that Boxdown-managed block is `installed`,
35
+ `missing`, or `outdated`. It only recognizes blocks wrapped in Boxdown's marker
36
+ comments; an unrelated OpenSSH `Host` entry with the same alias is not treated
37
+ as an installed Boxdown alias.
38
+
39
+ ## Proxy Flow
40
+
41
+ When OpenSSH launches `boxdown ssh-proxy`, Boxdown:
42
+
43
+ 1. Quietly refreshes the SSH config block.
44
+ 2. Ensures the per-workspace host key exists.
45
+ 3. Reuses a running devcontainer when possible.
46
+ 4. Starts the devcontainer when needed.
47
+ 5. Runs a throttled coding-agent CLI update preflight inside the container.
48
+ 6. Runs the container SSH bootstrap runtime.
49
+ 7. Bridges OpenSSH to `/usr/sbin/sshd -i` through `docker exec -i`.
50
+
51
+ This does not publish an SSH port. The SSH stream travels through Docker exec.
52
+
53
+ The coding-agent CLI update preflight covers already-running containers, where
54
+ `postStartCommand` does not necessarily run before a new SSH session. Its output
55
+ is routed to stderr so stdout remains reserved for SSH traffic.
56
+
57
+ ## Key Boundary
58
+
59
+ The private key stays on the host. The container receives only the public key,
60
+ mounted from a public-key-only runtime directory.
@@ -0,0 +1,83 @@
1
+ # Start Command
2
+
3
+ ## Commands
4
+
5
+ ```sh
6
+ boxdown start
7
+ boxdown codex
8
+ boxdown claude
9
+ boxdown cc
10
+ boxdown opencode
11
+ boxdown antigravity
12
+ ```
13
+
14
+ `start` targets the current directory by default and accepts:
15
+
16
+ ```sh
17
+ --workspace <path>
18
+ --recreate
19
+ ```
20
+
21
+ `boxdown shell` remains supported as an alias for `boxdown start`, but `start`
22
+ is the canonical command used in help and documentation.
23
+
24
+ The coding-agent aliases start or reuse the same workspace devcontainer and
25
+ launch the selected CLI directly:
26
+
27
+ - `boxdown codex` launches `codex`.
28
+ - `boxdown claude` and `boxdown cc` launch `claude`.
29
+ - `boxdown opencode` launches `opencode`.
30
+ - `boxdown antigravity` launches `agy`.
31
+
32
+ Pass agent-specific arguments after `--` so Boxdown options stay unambiguous:
33
+
34
+ ```sh
35
+ boxdown claude -- --continue
36
+ ```
37
+
38
+ ## Flow
39
+
40
+ 1. Resolve the workspace to a real absolute path.
41
+ 2. Ensure per-workspace SSH key material exists.
42
+ 3. Generate a Boxdown-owned devcontainer config.
43
+ 4. Install or reuse the pinned Dev Containers CLI.
44
+ 5. Run `devcontainer up --workspace-folder <repo> --override-config <config>`.
45
+ 6. Run container lifecycle hooks, including a best-effort coding-agent CLI refresh.
46
+ 7. Print a dynamic port hint when the configured published port is mapped.
47
+ 8. Run `devcontainer exec ... bash` to open an interactive shell.
48
+
49
+ Coding-agent aliases use the same startup flow but skip the port hint, run a
50
+ best-effort refresh for the selected agent, and exec the agent binary instead of
51
+ opening `bash`.
52
+
53
+ ## Terminal Width
54
+
55
+ Some terminal UIs behave poorly when a host terminal reports an extremely wide
56
+ PTY, especially from embedded terminals. Before opening the shell, Boxdown
57
+ clamps interactive terminal width to 120 columns when the reported width is
58
+ larger.
59
+
60
+ Override the default width when you want a wider layout:
61
+
62
+ ```sh
63
+ BOXDOWN_TTY_MAX_COLUMNS=180 boxdown start
64
+ ```
65
+
66
+ Disable the normalization entirely when you want the container shell to use the
67
+ host terminal size unchanged:
68
+
69
+ ```sh
70
+ BOXDOWN_TTY_NORMALIZE=0 boxdown start
71
+ ```
72
+
73
+ ## Recreate
74
+
75
+ `--recreate` passes `--remove-existing-container` to the Dev Containers CLI.
76
+ Use it when changing create-time settings such as image, features, mounts, or
77
+ Docker `runArgs`.
78
+
79
+ ## Port Hint
80
+
81
+ The v1 asset config publishes container port `3000` with a dynamic host port.
82
+ After `up`, Boxdown asks Docker for the mapped host binding and prints the
83
+ result as an HTTP URL when available.
@@ -0,0 +1,63 @@
1
+ # Testing
2
+
3
+ ## Standard Checks
4
+
5
+ Run these before opening a PR:
6
+
7
+ ```sh
8
+ pnpm run lint
9
+ pnpm run build
10
+ pnpm run test
11
+ ```
12
+
13
+ `pnpm run lint` includes ESLint and markdown lint. Documentation under `docs/`
14
+ is intentionally linted.
15
+
16
+ ## Unit Test Strategy
17
+
18
+ Unit tests should avoid starting Docker. Prefer pure tests for:
19
+
20
+ - CLI parsing and command aliases.
21
+ - Workspace path resolution and state directory selection.
22
+ - Generated devcontainer config shape.
23
+ - SSH config block creation and idempotent replacement.
24
+ - Lifecycle status and doctor output formatting.
25
+ - Workspace metadata and list output formatting.
26
+ - Safety invariants, such as not packaging `.ssh/` key material.
27
+
28
+ Use temporary directories for workspace and state tests. Do not write to the
29
+ user's real SSH config in unit tests.
30
+
31
+ ## Build and CLI Smoke Tests
32
+
33
+ After `pnpm run build`, smoke test the built binary:
34
+
35
+ ```sh
36
+ node dist/bin/cli.cjs --help
37
+ ```
38
+
39
+ Use a dry-run pack check when changing package assets or `package.json.files`:
40
+
41
+ ```sh
42
+ npm pack --dry-run --json
43
+ ```
44
+
45
+ Confirm `assets/devcontainer/**` is included and `.ssh/` is not.
46
+
47
+ ## Manual Acceptance
48
+
49
+ Manual Docker acceptance is heavier and should be done intentionally:
50
+
51
+ ```sh
52
+ boxdown start --workspace /path/to/repo
53
+ boxdown list
54
+ boxdown list --json
55
+ boxdown status --workspace /path/to/repo
56
+ boxdown status --workspace /path/to/repo --json
57
+ boxdown doctor --workspace /path/to/repo
58
+ boxdown ssh-config install --workspace /path/to/repo
59
+ ssh <repo-name>-devcontainer 'whoami && pwd'
60
+ ```
61
+
62
+ Run this from at least two repositories when changing workspace isolation,
63
+ container lookup, SSH config generation, or generated config behavior.
package/docs/todo.md ADDED
@@ -0,0 +1,170 @@
1
+ # Todo and Next Plans
2
+
3
+ This file is a handoff for the next Boxdown implementation session. It assumes
4
+ v1 exists as a CLI-first package that stores reusable devcontainer assets under
5
+ `assets/devcontainer/`, generates per-workspace override config outside target
6
+ repositories, and supports start (with `shell` as an alias), SSH proxy, SSH
7
+ config install, lifecycle status/stop/down/doctor commands, and GitHub auth
8
+ refresh commands.
9
+
10
+ ## Current Baseline
11
+
12
+ - Boxdown has no root `.devcontainer/` directory.
13
+ - Reusable devcontainer source lives in `assets/devcontainer/`.
14
+ - Generated config uses the Dev Containers CLI with `--workspace-folder` and
15
+ `--override-config`.
16
+ - Workspace cache state defaults to `~/.cache/boxdown`.
17
+ - Workspace persistent state defaults to `~/.local/share/boxdown`.
18
+ - Host private SSH keys stay on the host; the container receives only a public
19
+ key mount.
20
+ - Lifecycle commands report status, color-code unhealthy status output, check
21
+ host prerequisites, stop containers, and remove containers without deleting
22
+ Boxdown state or SSH keys.
23
+ - Unit tests cover parsing, generated config shape, SSH config block generation,
24
+ lifecycle output formatting, and packaging safety.
25
+
26
+ ## Next Implementation Tracks
27
+
28
+ ### 1. Manual Acceptance and Runtime Fixes (completed)
29
+
30
+ The real Docker and SSH workflow was tested from linked local `boxdown`
31
+ commands. Runtime fixes from that pass included interactive terminal width
32
+ normalization and command alias cleanup.
33
+
34
+ Acceptance commands:
35
+
36
+ ```sh
37
+ boxdown start --workspace ~/projects/repos/gh-cp
38
+ boxdown ssh-config install --workspace ~/projects/repos/gh-cp
39
+ ssh gh-cp-devcontainer 'whoami && pwd'
40
+
41
+ boxdown start --workspace ~/projects/repos/lirantaldotcom
42
+ boxdown ssh-config install --workspace ~/projects/repos/lirantaldotcom
43
+ ssh lirantaldotcom-devcontainer 'whoami && pwd'
44
+ ```
45
+
46
+ ### 2. Lifecycle Commands and CLI UX (completed)
47
+
48
+ Added practical commands around the existing start flow:
49
+
50
+ - `boxdown status` to show workspace, generated config path, container ID,
51
+ running state, SSH alias, and key paths.
52
+ - `boxdown stop` to stop the workspace container.
53
+ - `boxdown down` to remove the workspace container.
54
+ - `boxdown doctor` to validate Node, Docker, SSH, packaged `@devcontainers/cli`,
55
+ optional `gh`, and asset presence.
56
+ - `boxdown status --json` for machine-readable status output.
57
+
58
+ Lifecycle commands keep destructive behavior explicit and conservative. They do
59
+ not remove generated state or SSH keys.
60
+
61
+ ### 3. Editor Stub Support
62
+
63
+ Add an optional command for users who want native VS Code or Cursor Dev
64
+ Containers discovery:
65
+
66
+ ```sh
67
+ boxdown init-editor-stub
68
+ ```
69
+
70
+ The stub should be opt-in and small. It can either create a minimal
71
+ `.devcontainer/devcontainer.json` that delegates to Boxdown-generated config or
72
+ document why native editor discovery still requires a project-local file.
73
+
74
+ Do not make editor stubs part of the default workflow. The v1 invariant is that
75
+ target repositories stay clean unless the user explicitly asks for a file.
76
+
77
+ ### 4. Customization and Profiles
78
+
79
+ Design a small user configuration surface for common changes:
80
+
81
+ - Extra forwarded ports.
82
+ - Extra host mounts for agent config directories.
83
+ - Feature toggles for tools such as Snyk, 1Password, Codex CLI, or APM.
84
+ - Image or Node version overrides.
85
+ - Per-project SSH alias defaults.
86
+
87
+ Prefer a Boxdown-owned config file under user config/state locations before
88
+ adding target-repo config. If target-repo config is needed, make precedence and
89
+ security implications explicit.
90
+
91
+ ### 5. Dev Container Feature Packaging
92
+
93
+ Investigate moving the container-side OpenSSH bootstrap and runtime setup into a
94
+ proper Dev Container Feature. This could make lifecycle behavior more
95
+ spec-native and reduce reliance on mounted shell assets.
96
+
97
+ Questions to answer:
98
+
99
+ - Should the feature be published to GHCR?
100
+ - Does publishing a feature complicate local development?
101
+ - Which setup should remain as mounted assets for offline or unreleased use?
102
+
103
+ ### 6. Asset Sync Workflow
104
+
105
+ Decide whether `gh-cp/.devcontainer` remains the canonical source or whether
106
+ Boxdown now owns the canonical asset copy.
107
+
108
+ If `gh-cp` remains canonical, add a documented sync command or maintainer script
109
+ that copies only tracked files and excludes `.ssh/`. If Boxdown becomes
110
+ canonical, update docs in both repos so future changes happen in the right
111
+ place.
112
+
113
+ ### 7. Integration Test Harness
114
+
115
+ Add tests beyond pure unit coverage without making CI fragile:
116
+
117
+ - Fake `docker`, `npm`, `gh`, and `devcontainer` binaries for command argument
118
+ assertions.
119
+ - Temporary HOME, cache, data, and SSH config paths.
120
+ - Golden tests for generated `devcontainer.json`.
121
+ - Optional local-only integration tests that start real containers.
122
+
123
+ Keep real Docker tests out of default CI until they are fast, deterministic, and
124
+ safe for GitHub Actions runners.
125
+
126
+ ### 8. Release Polish
127
+
128
+ Before the first serious npm release:
129
+
130
+ - Confirm package contents with `npm pack --dry-run --json`.
131
+ - Confirm `npx boxdown --help` works from a packed tarball.
132
+ - Add examples for common agent workflows.
133
+ - Confirm the changeset summary is user-facing.
134
+ - Consider whether `dist` should be committed or only generated in release CI.
135
+
136
+ ## What a Fresh Session Needs to Know
137
+
138
+ Read these files first:
139
+
140
+ - `docs/architecture.md`
141
+ - `docs/features/generated-config-and-state.md`
142
+ - `docs/features/ssh-config-and-proxy.md`
143
+ - `src/config.ts`
144
+ - `src/devcontainer.ts`
145
+ - `src/ssh-config.ts`
146
+ - `src/ssh-key.ts`
147
+
148
+ Confirm these facts before implementation:
149
+
150
+ - Whether real Docker/SSH manual acceptance is allowed in the current session.
151
+ - Which host platforms are in scope for the next release: macOS, Linux, WSL, or
152
+ Windows OpenSSH.
153
+ - Whether Boxdown or `gh-cp` should own canonical devcontainer assets going
154
+ forward.
155
+ - Whether target repositories may ever contain generated files by default.
156
+ - Whether user configuration should live only in Boxdown state or may be read
157
+ from the target repository.
158
+ - Which editor gets first-class support if editor stubs are built.
159
+ - Whether GitHub auth refresh should keep using `--insecure-storage` inside the
160
+ container or offer a more configurable credential strategy.
161
+
162
+ ## Suggested Fresh-Session Prompt
163
+
164
+ ```text
165
+ Continue Boxdown after v1. Read docs/todo.md, docs/architecture.md, and the
166
+ feature docs first. Start with manual Docker and SSH acceptance for two repos,
167
+ then fix any runtime issues while preserving the invariants: no root
168
+ .devcontainer in Boxdown, no .devcontainer copied into target repos, no private
169
+ SSH key mounted into containers, and generated config/state owned by Boxdown.
170
+ ```
package/package.json ADDED
@@ -0,0 +1,128 @@
1
+ {
2
+ "name": "boxdown",
3
+ "version": "1.0.0",
4
+ "description": "Run a reusable devcontainer sandbox for any local project",
5
+ "types": "dist/main.d.mts",
6
+ "type": "module",
7
+ "bin": {
8
+ "boxdown": "./dist/bin/cli.cjs"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "import": {
13
+ "types": "./dist/main.d.mts",
14
+ "default": "./dist/main.mjs"
15
+ },
16
+ "require": {
17
+ "types": "./dist/main.d.cts",
18
+ "default": "./dist/main.cjs"
19
+ },
20
+ "default": "./dist/main.mjs"
21
+ },
22
+ "./dist/*": {
23
+ "types": "./dist/*.d.mts",
24
+ "import": "./dist/*.mjs",
25
+ "require": "./dist/*.cjs"
26
+ }
27
+ },
28
+ "engines": {
29
+ "node": ">=24.0.0",
30
+ "pnpm": ">=11.0.0"
31
+ },
32
+ "devEngines": {
33
+ "packageManager": {
34
+ "name": "pnpm",
35
+ "version": ">=11.0.0",
36
+ "onFail": "download"
37
+ }
38
+ },
39
+ "files": [
40
+ "assets",
41
+ "docs",
42
+ "dist",
43
+ "src",
44
+ "bin"
45
+ ],
46
+ "author": {
47
+ "name": "Liran Tal",
48
+ "email": "liran.tal@gmail.com",
49
+ "url": "git+https://github.com/lirantal"
50
+ },
51
+ "publishConfig": {
52
+ "provenance": true,
53
+ "access": "public"
54
+ },
55
+ "license": "Apache-2.0",
56
+ "keywords": [
57
+ "devcontainer",
58
+ "docker",
59
+ "development-environment",
60
+ "ssh",
61
+ "sandbox"
62
+ ],
63
+ "homepage": "https://github.com/lirantal/boxdown",
64
+ "bugs": {
65
+ "url": "https://github.com/lirantal/boxdown/issues"
66
+ },
67
+ "repository": {
68
+ "type": "git",
69
+ "url": "https://github.com/lirantal/boxdown.git"
70
+ },
71
+ "dependencies": {
72
+ "@devcontainers/cli": "0.84.1"
73
+ },
74
+ "devDependencies": {
75
+ "@changesets/changelog-github": "^0.5.0",
76
+ "@changesets/cli": "^2.27.7",
77
+ "@eslint/js": "^10.0.1",
78
+ "@types/node": "^25.5.0",
79
+ "c8": "^11.0.0",
80
+ "eslint": "^10.2.1",
81
+ "eslint-plugin-n": "^17.24.0",
82
+ "eslint-plugin-security": "^4.0.0",
83
+ "husky": "^9.0.11",
84
+ "lint-staged": "^16.2.7",
85
+ "markdownlint-cli": "0.48.0",
86
+ "tsdown": "^0.21.5",
87
+ "tsx": "^4.19.4",
88
+ "typescript": "^5.5.3",
89
+ "typescript-eslint": "^8.59.0",
90
+ "validate-conventional-commit": "^1.0.4"
91
+ },
92
+ "lint-staged": {
93
+ "**/*.{js,json}": [
94
+ "pnpm run lint:fix"
95
+ ]
96
+ },
97
+ "c8": {
98
+ "exclude": [
99
+ "dist/**",
100
+ "coverage/**",
101
+ "__tests__/**",
102
+ "**/*.test.ts",
103
+ "**/*.test.js"
104
+ ],
105
+ "include": [
106
+ "src/**"
107
+ ],
108
+ "reporter": [
109
+ "text",
110
+ "lcov",
111
+ "html"
112
+ ]
113
+ },
114
+ "scripts": {
115
+ "start": "tsx src/bin/cli.ts",
116
+ "build": "tsc && tsdown",
117
+ "lint": "eslint . && pnpm run lint:markdown",
118
+ "lint:markdown": "markdownlint -c .github/.markdownlint.yml -i 'apm_modules/**' -i '.git' -i '__tests__' -i '.github' -i '.changeset' -i 'CODE_OF_CONDUCT.md' -i 'CHANGELOG.md' -i 'node_modules' -i 'dist' '**/**.md'",
119
+ "lint:markdown:fix": "markdownlint -c .github/.markdownlint.yml -i 'apm_modules/**' -i '.git' -i '__tests__' -i '.github' -i '.changeset' -i 'CODE_OF_CONDUCT.md' -i 'CHANGELOG.md' -i 'node_modules' -i 'dist' '**/**.md' --fix",
120
+ "lint:fix": "eslint . --fix",
121
+ "test": "c8 node --import tsx --test __tests__/**/*.test.ts",
122
+ "test:watch": "c8 node --import tsx --test --watch __tests__/**/*.test.ts",
123
+ "coverage:view": "open coverage/lcov-report/index.html",
124
+ "version": "changeset version",
125
+ "release": "changeset publish",
126
+ "release:create": "changeset && git add .changeset && git commit -m \"chore: release\" && git push origin HEAD --no-verify"
127
+ }
128
+ }
package/src/bin/cli.ts ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from '../main.ts'
3
+
4
+ runCli().then((exitCode) => {
5
+ process.exitCode = exitCode
6
+ }, (error: unknown) => {
7
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`)
8
+ process.exitCode = 1
9
+ })
@@ -0,0 +1,22 @@
1
+ export type CodingAgentCli = 'codex' | 'opencode' | 'claude' | 'antigravity'
2
+ export type CodingAgentCommandAlias = CodingAgentCli | 'cc'
3
+
4
+ const CODING_AGENT_ALIASES: Record<CodingAgentCommandAlias, CodingAgentCli> = {
5
+ codex: 'codex',
6
+ opencode: 'opencode',
7
+ claude: 'claude',
8
+ cc: 'claude',
9
+ antigravity: 'antigravity'
10
+ }
11
+
12
+ export function codingAgentFromCommand (command: string): CodingAgentCli | undefined {
13
+ return CODING_AGENT_ALIASES[command as CodingAgentCommandAlias]
14
+ }
15
+
16
+ export function codingAgentBinary (agent: CodingAgentCli): string {
17
+ if (agent === 'antigravity') {
18
+ return 'agy'
19
+ }
20
+
21
+ return agent
22
+ }