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,67 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ DEVCONTAINER_DIR="$(cd "${HOOKS_DIR}/.." && pwd)"
6
+
7
+ main() {
8
+ configure_local_git
9
+ install_openssh_server
10
+ install_apm
11
+ install_or_update_coding_agent_clis
12
+ install_1password_cli
13
+ install_snyk_cli
14
+ run_deps_install
15
+ }
16
+
17
+ configure_local_git() {
18
+ # Local git prefs only apply inside a repository; skip when there is no .git (avoids postCreate failure).
19
+ if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
20
+ git config --local commit.gpgsign false
21
+ git config --local core.pager 'less -R'
22
+ git config --local credential.https://github.com.helper '!gh auth git-credential'
23
+ fi
24
+ }
25
+
26
+ install_apm() {
27
+ # Agent Package Manager: https://github.com/microsoft/apm
28
+ curl -sSL https://aka.ms/apm-unix | sh
29
+ }
30
+
31
+ install_or_update_coding_agent_clis() {
32
+ bash "${DEVCONTAINER_DIR}/utils/coding-agent-cli-update.sh" install ||
33
+ echo "post-create: warning: one or more coding-agent CLI refreshes failed." >&2
34
+ }
35
+
36
+ install_openssh_server() {
37
+ bash "${DEVCONTAINER_DIR}/utils/ssh-bootstrap.sh" install
38
+ }
39
+
40
+ install_snyk_cli() {
41
+ # https://docs.snyk.io/snyk-cli/install-the-snyk-cli
42
+ local url
43
+ case "$(uname -m)" in
44
+ aarch64 | arm64) url="https://static.snyk.io/cli/latest/snyk-linux-arm64" ;;
45
+ x86_64 | amd64) url="https://static.snyk.io/cli/latest/snyk-linux" ;;
46
+ *)
47
+ echo "post-create: skipping Snyk CLI (unsupported arch: $(uname -m))" >&2
48
+ return 0
49
+ ;;
50
+ esac
51
+ curl --compressed -fsSL "${url}" -o /tmp/snyk
52
+ chmod +x /tmp/snyk
53
+ sudo mv -f /tmp/snyk /usr/local/bin/snyk
54
+ }
55
+
56
+ install_1password_cli() {
57
+ local op_version="2.32.1"
58
+ curl -fsSL "https://cache.agilebits.com/dist/1P/op2/pkg/v${op_version}/op_linux_arm64_v${op_version}.zip" -o /tmp/op.zip
59
+ python3 -c "import zipfile; zipfile.ZipFile('/tmp/op.zip').extract('op', '/tmp')"
60
+ sudo mv /tmp/op /usr/local/bin/op && chmod +x /usr/local/bin/op && rm /tmp/op.zip
61
+ }
62
+
63
+ run_deps_install() {
64
+ bash "${DEVCONTAINER_DIR}/utils/deps-install.sh"
65
+ }
66
+
67
+ main "$@"
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+ # post-start: runs after each container start (postStartCommand in devcontainer.json).
3
+ # Naming matches post-create.sh; extend with more steps as needed (e.g. source scripts from .devcontainer/utils/).
4
+
5
+ set -euo pipefail
6
+
7
+ HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ DEVCONTAINER_DIR="$(cd "${HOOKS_DIR}/.." && pwd)"
9
+
10
+ main() {
11
+ configure_sshd_runtime
12
+ refresh_coding_agent_clis
13
+ remove_ephemeral_env_file_if_present
14
+ }
15
+
16
+ configure_sshd_runtime() {
17
+ bash "${DEVCONTAINER_DIR}/utils/ssh-bootstrap.sh" runtime
18
+ }
19
+
20
+ refresh_coding_agent_clis() {
21
+ bash "${DEVCONTAINER_DIR}/utils/coding-agent-cli-update.sh" maybe-update ||
22
+ echo "post-start: warning: one or more coding-agent CLI refreshes failed." >&2
23
+ }
24
+
25
+ # When initializeCommand + runArgs inject secrets via .env.development, remove the file
26
+ # after start so it is not left on disk and tooling that assumes absence does not break.
27
+ remove_ephemeral_env_file_if_present() {
28
+ local env_file=".env.development"
29
+ if [[ -f "$env_file" ]]; then
30
+ rm -f "$env_file"
31
+ fi
32
+ }
33
+
34
+ main "$@"
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Install/update a host SSH config alias for this repo's portless devcontainer SSH flow.
4
+
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ WORKSPACE_FOLDER="$(cd "${SCRIPT_DIR}/.." && pwd -P)"
9
+ REPO_NAME="$(basename "${WORKSPACE_FOLDER}")"
10
+ HOST_ALIAS="${DEVCONTAINER_SSH_HOST_ALIAS:-${REPO_NAME}-devcontainer}"
11
+ SSH_CONFIG="${DEVCONTAINER_SSH_CONFIG:-${HOME}/.ssh/config}"
12
+ SSH_KEY_DIR="${DEVCONTAINER_SSH_KEY_DIR:-${SCRIPT_DIR}/.ssh}"
13
+ SSH_KEY_PATH="${DEVCONTAINER_SSH_KEY_PATH:-${SSH_KEY_DIR}/id_ed25519}"
14
+ START_SCRIPT="${SCRIPT_DIR}/start.sh"
15
+ BEGIN_MARKER="# BEGIN ${HOST_ALIAS} devcontainer ssh"
16
+ END_MARKER="# END ${HOST_ALIAS} devcontainer ssh"
17
+ QUIET=false
18
+
19
+ usage() {
20
+ cat <<EOF
21
+ Usage: $(basename "$0") [options]
22
+
23
+ Install or update a host SSH config alias for this repo's devcontainer.
24
+
25
+ Options:
26
+ --alias <name> SSH host alias to write (default: ${HOST_ALIAS})
27
+ --config <path> SSH config file to update (default: ${SSH_CONFIG})
28
+ --quiet Only print errors.
29
+ --help, -h Show this help and exit.
30
+
31
+ Environment overrides:
32
+ DEVCONTAINER_SSH_HOST_ALIAS
33
+ DEVCONTAINER_SSH_CONFIG
34
+ DEVCONTAINER_SSH_KEY_DIR
35
+ DEVCONTAINER_SSH_KEY_PATH
36
+ EOF
37
+ }
38
+
39
+ die() {
40
+ printf '%s\n' "$*" >&2
41
+ exit 1
42
+ }
43
+
44
+ log() {
45
+ if [ "$QUIET" != true ]; then
46
+ printf '%s\n' "$*"
47
+ fi
48
+ }
49
+
50
+ ssh_config_quote() {
51
+ local value="$1"
52
+ value="${value//\\/\\\\}"
53
+ value="${value//\"/\\\"}"
54
+ printf '"%s"' "$value"
55
+ }
56
+
57
+ ensure_host_ssh_key() {
58
+ if ! command -v ssh-keygen >/dev/null 2>&1; then
59
+ die "ssh-keygen is required for devcontainer SSH setup."
60
+ fi
61
+
62
+ mkdir -p "$SSH_KEY_DIR"
63
+ chmod 0700 "$SSH_KEY_DIR"
64
+
65
+ if [ ! -f "$SSH_KEY_PATH" ]; then
66
+ log "Generating devcontainer SSH identity: $SSH_KEY_PATH"
67
+ ssh-keygen -t ed25519 -f "$SSH_KEY_PATH" -N "" -C "${REPO_NAME}-devcontainer" >/dev/null
68
+ fi
69
+
70
+ if [ ! -f "${SSH_KEY_PATH}.pub" ]; then
71
+ ssh-keygen -y -f "$SSH_KEY_PATH" > "${SSH_KEY_PATH}.pub"
72
+ fi
73
+
74
+ chmod 0600 "$SSH_KEY_PATH"
75
+ chmod 0644 "${SSH_KEY_PATH}.pub"
76
+ }
77
+
78
+ write_ssh_config_block() {
79
+ local ssh_dir
80
+ local tmp_file
81
+ local start_script_quoted
82
+ local key_path_quoted
83
+ local host_alias_quoted
84
+
85
+ ssh_dir="$(dirname "$SSH_CONFIG")"
86
+ mkdir -p "$ssh_dir"
87
+ chmod 0700 "$ssh_dir"
88
+ touch "$SSH_CONFIG"
89
+ chmod 0600 "$SSH_CONFIG"
90
+
91
+ tmp_file="$(mktemp)"
92
+ awk -v begin="$BEGIN_MARKER" -v end="$END_MARKER" '
93
+ $0 == begin { skip = 1; next }
94
+ $0 == end { skip = 0; next }
95
+ !skip { print }
96
+ ' "$SSH_CONFIG" > "$tmp_file"
97
+
98
+ start_script_quoted="$(ssh_config_quote "$START_SCRIPT")"
99
+ key_path_quoted="$(ssh_config_quote "$SSH_KEY_PATH")"
100
+ host_alias_quoted="$(ssh_config_quote "$HOST_ALIAS")"
101
+
102
+ {
103
+ sed -e '${/^$/d;}' "$tmp_file"
104
+ printf '\n%s\n' "$BEGIN_MARKER"
105
+ printf 'Host %s\n' "$HOST_ALIAS"
106
+ printf ' HostName %s\n' "$HOST_ALIAS"
107
+ printf ' User node\n'
108
+ printf ' IdentityFile none\n'
109
+ printf ' IdentityFile %s\n' "$key_path_quoted"
110
+ printf ' IdentitiesOnly yes\n'
111
+ printf ' ProxyCommand env DEVCONTAINER_SSH_HOST_ALIAS=%s /bin/bash %s --ssh-proxy\n' "$host_alias_quoted" "$start_script_quoted"
112
+ printf ' StrictHostKeyChecking no\n'
113
+ printf ' UserKnownHostsFile /dev/null\n'
114
+ printf ' LogLevel ERROR\n'
115
+ printf '%s\n' "$END_MARKER"
116
+ } > "${tmp_file}.next"
117
+
118
+ if cmp -s "$SSH_CONFIG" "${tmp_file}.next"; then
119
+ log "SSH alias already up to date: ${HOST_ALIAS}"
120
+ rm -f "${tmp_file}.next"
121
+ else
122
+ mv "${tmp_file}.next" "$SSH_CONFIG"
123
+ log "Installed SSH alias: ${HOST_ALIAS}"
124
+ fi
125
+
126
+ rm -f "$tmp_file"
127
+ chmod 0600 "$SSH_CONFIG"
128
+ }
129
+
130
+ while [ $# -gt 0 ]; do
131
+ case "$1" in
132
+ --help | -h)
133
+ usage
134
+ exit 0
135
+ ;;
136
+ --alias)
137
+ [ $# -ge 2 ] || die "--alias requires a value."
138
+ HOST_ALIAS="$2"
139
+ BEGIN_MARKER="# BEGIN ${HOST_ALIAS} devcontainer ssh"
140
+ END_MARKER="# END ${HOST_ALIAS} devcontainer ssh"
141
+ shift 2
142
+ ;;
143
+ --config)
144
+ [ $# -ge 2 ] || die "--config requires a value."
145
+ SSH_CONFIG="$2"
146
+ shift 2
147
+ ;;
148
+ --quiet)
149
+ QUIET=true
150
+ shift
151
+ ;;
152
+ *)
153
+ die "Unknown option: $1"
154
+ ;;
155
+ esac
156
+ done
157
+
158
+ ensure_host_ssh_key
159
+ write_ssh_config_block
160
+
161
+ if [ "$QUIET" != true ]; then
162
+ cat <<EOF
163
+ SSH config: ${SSH_CONFIG}
164
+ Identity file: ${SSH_KEY_PATH}
165
+
166
+ Validate with:
167
+ ssh ${HOST_ALIAS} 'whoami && pwd'
168
+
169
+ Use this host alias in Cursor, Claude, or any other SSH client:
170
+ ${HOST_ALIAS}
171
+ EOF
172
+ fi