create-node-lib 2.16.7 → 2.17.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/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/template/.devcontainer/devcontainer.json +53 -23
- package/template/.devcontainer/post-create.sh +43 -22
- package/template/.devcontainer/post-start.sh +18 -0
- package/template/.devcontainer/start.sh +45 -10
- package/template/.devcontainer/utils/deps-install.sh +87 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# [2.17.0](https://github.com/lirantal/create-node-lib/compare/v2.16.7...v2.17.0) (2026-05-03)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* chmod executable files ([034b771](https://github.com/lirantal/create-node-lib/commit/034b77199ae06936272e8b6afc8a61e98132e9bc))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* devcontainer updates ([d5618de](https://github.com/lirantal/create-node-lib/commit/d5618def17a07c13b438795d96e5e26bdffab770))
|
|
12
|
+
|
|
1
13
|
## [2.16.7](https://github.com/lirantal/create-node-lib/compare/v2.16.6...v2.16.7) (2026-05-01)
|
|
2
14
|
|
|
3
15
|
|
package/package.json
CHANGED
|
@@ -10,15 +10,44 @@
|
|
|
10
10
|
"shellautocompletion": true
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
|
-
//
|
|
14
|
-
"forwardPorts": [
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
// Ask the editor to forward these container ports (no Docker appPort).
|
|
14
|
+
"forwardPorts": [8787, 3005, 3001, 3000],
|
|
15
|
+
|
|
16
|
+
"portsAttributes": {
|
|
17
|
+
"8787": {
|
|
18
|
+
"label": "Hono Dev Server",
|
|
19
|
+
"onAutoForward": "notify"
|
|
20
|
+
},
|
|
21
|
+
"3005": {
|
|
22
|
+
"label": "Nuxt Dev Server",
|
|
23
|
+
"onAutoForward": "notify"
|
|
24
|
+
},
|
|
25
|
+
"3001": {
|
|
26
|
+
"label": "Nuxt Preview Server",
|
|
27
|
+
"onAutoForward": "silent"
|
|
28
|
+
},
|
|
29
|
+
"3000": {
|
|
30
|
+
"label": "Published dev server",
|
|
31
|
+
"protocol": "http",
|
|
32
|
+
"onAutoForward": "notify",
|
|
33
|
+
"requireLocalPort": false
|
|
34
|
+
},
|
|
35
|
+
// only enable when running Caddy http proxy in the container
|
|
36
|
+
// "80": {
|
|
37
|
+
// "label": "Caddy HTTP",
|
|
38
|
+
// "onAutoForward": "notify"
|
|
39
|
+
// },
|
|
40
|
+
// "443": {
|
|
41
|
+
// "label": "Caddy HTTPS",
|
|
42
|
+
// "onAutoForward": "notify"
|
|
43
|
+
// }
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
"otherPortsAttributes": {
|
|
47
|
+
"onAutoForward": "notify",
|
|
48
|
+
"requireLocalPort": false
|
|
49
|
+
},
|
|
50
|
+
|
|
22
51
|
"mounts": [
|
|
23
52
|
"source=${localEnv:HOME}/.gitconfig,target=/home/node/.gitconfig,type=bind,consistency=cached",
|
|
24
53
|
// mount host user home directories for agents:
|
|
@@ -26,21 +55,22 @@
|
|
|
26
55
|
// "source=${localEnv:HOME}/.gemini,target=/home/node/.claude,type=bind,consistency=cached",
|
|
27
56
|
// "source=${localEnv:HOME}/.codex,target=/home/node/.codex,type=bind,consistency=cached"
|
|
28
57
|
],
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
58
|
+
|
|
59
|
+
// Initialize optional host-side secrets before container create/start.
|
|
60
|
+
"initializeCommand": "bash .devcontainer/initialize.sh",
|
|
61
|
+
// After up, discover the published host binding, e.g.:
|
|
62
|
+
// docker port <container-name-or-id> 3000/tcp
|
|
63
|
+
"runArgs": [
|
|
64
|
+
// publish container port 3000 with dynamic host port (CLI / start.sh)
|
|
65
|
+
"-p",
|
|
66
|
+
"127.0.0.1::3000",
|
|
67
|
+
// pass the development environment file to the container
|
|
68
|
+
"--env-file",
|
|
69
|
+
"${localWorkspaceFolder}/.env.development"
|
|
70
|
+
],
|
|
35
71
|
// --
|
|
36
|
-
"postCreateCommand":
|
|
37
|
-
|
|
38
|
-
"post-create": "bash .devcontainer/post-create.sh"
|
|
39
|
-
},
|
|
40
|
-
"postStartCommand": {
|
|
41
|
-
// "rm-env-file": "if [ -n './.env.development' ]; then rm -f './.env.development'; fi;",
|
|
42
|
-
"start-dev": "[ -f package.json ] && pnpm run dev || true"
|
|
43
|
-
},
|
|
72
|
+
"postCreateCommand": "bash .devcontainer/post-create.sh",
|
|
73
|
+
"postStartCommand": "bash .devcontainer/post-start.sh",
|
|
44
74
|
"remoteUser": "node",
|
|
45
75
|
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
|
46
76
|
"containerEnv": {
|
|
@@ -1,25 +1,46 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
set -e
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
#
|
|
24
|
-
|
|
25
|
-
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
|
|
6
|
+
main() {
|
|
7
|
+
configure_local_git
|
|
8
|
+
install_apm
|
|
9
|
+
# install_opencode_cli
|
|
10
|
+
install_1password_cli
|
|
11
|
+
run_deps_install
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
configure_local_git() {
|
|
15
|
+
# Local git prefs only apply inside a repository; skip when there is no .git (avoids postCreate failure).
|
|
16
|
+
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
17
|
+
git config --local commit.gpgsign false
|
|
18
|
+
git config --local core.pager 'less -R'
|
|
19
|
+
fi
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
install_apm() {
|
|
23
|
+
# Agent Package Manager: https://github.com/microsoft/apm
|
|
24
|
+
curl -sSL https://aka.ms/apm-unix | sh
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
install_opencode_cli() {
|
|
28
|
+
curl -fsSL https://opencode.ai/install | bash
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Optional: Snyk CLI
|
|
32
|
+
# curl --compressed https://static.snyk.io/cli/latest/snyk-linux-arm64 -o snyk
|
|
33
|
+
# chmod +x ./snyk && sudo mv -f ./snyk /usr/local/bin/snyk
|
|
34
|
+
|
|
35
|
+
install_1password_cli() {
|
|
36
|
+
local op_version="2.32.1"
|
|
37
|
+
curl -fsSL "https://cache.agilebits.com/dist/1P/op2/pkg/v${op_version}/op_linux_arm64_v${op_version}.zip" -o /tmp/op.zip
|
|
38
|
+
python3 -c "import zipfile; zipfile.ZipFile('/tmp/op.zip').extract('op', '/tmp')"
|
|
39
|
+
sudo mv /tmp/op /usr/local/bin/op && chmod +x /usr/local/bin/op && rm /tmp/op.zip
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
run_deps_install() {
|
|
43
|
+
bash "${SCRIPT_DIR}/utils/deps-install.sh"
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
main "$@"
|
|
@@ -0,0 +1,18 @@
|
|
|
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
|
+
main() {
|
|
6
|
+
remove_ephemeral_env_file_if_present
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
# When initializeCommand + runArgs inject secrets via .env.development, remove the file
|
|
10
|
+
# after start so it is not left on disk and tooling that assumes absence does not break.
|
|
11
|
+
remove_ephemeral_env_file_if_present() {
|
|
12
|
+
local env_file=".env.development"
|
|
13
|
+
if [[ -f "$env_file" ]]; then
|
|
14
|
+
rm -f "$env_file"
|
|
15
|
+
fi
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
main "$@"
|
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
# @summary Start the Dev Container for this workspace and attach an interactive shell.
|
|
5
5
|
#
|
|
6
6
|
# Uses @devcontainers/cli to run `devcontainer up` then `devcontainer exec bash`.
|
|
7
|
-
# Host port publishing
|
|
8
|
-
#
|
|
9
|
-
#
|
|
7
|
+
# Host port publishing comes from **runArgs** in devcontainer.json (e.g. `-p` and
|
|
8
|
+
# `127.0.0.1::<containerPort>` for dynamic host binding). After `devcontainer up`, this
|
|
9
|
+
# script reads that container port from runArgs and prints the mapped URL via `docker port`.
|
|
10
10
|
#
|
|
11
11
|
# @usage
|
|
12
12
|
# .devcontainer/start.sh [options]
|
|
13
13
|
#
|
|
14
14
|
# @options
|
|
15
15
|
# --recreate Remove the existing dev container for this workspace before `up`, so
|
|
16
|
-
# changes to
|
|
16
|
+
# changes to runArgs (or other create-time settings) take effect.
|
|
17
17
|
# --help, -h Print usage and exit.
|
|
18
18
|
#
|
|
19
19
|
# @example
|
|
@@ -38,15 +38,25 @@ Then open an interactive bash session inside the container.
|
|
|
38
38
|
|
|
39
39
|
Options:
|
|
40
40
|
--recreate Remove the existing dev container for this workspace before starting,
|
|
41
|
-
so Docker picks up new settings (e.g.
|
|
41
|
+
so Docker picks up new settings (e.g. runArgs / port mappings).
|
|
42
42
|
--help, -h Show this help and exit.
|
|
43
43
|
|
|
44
44
|
Notes:
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
Port publishing uses runArgs (Docker -p ...::<containerPort>). The script greps that
|
|
46
|
+
container port from devcontainer.json for the post-up URL hint.
|
|
47
47
|
EOF
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
# Container-side TCP port published via runArgs, e.g. "127.0.0.1::3000" (Docker -p host::ctr).
|
|
51
|
+
# Requires GNU grep (-P); same as the containerId parse below.
|
|
52
|
+
publish_container_port_from_devcontainer_json() {
|
|
53
|
+
local f="$SCRIPT_DIR/devcontainer.json"
|
|
54
|
+
if [ ! -r "$f" ]; then
|
|
55
|
+
return 1
|
|
56
|
+
fi
|
|
57
|
+
sed 's|//.*||' "$f" | grep -oP '"[0-9.]+\:\:\K[0-9]+(?=")' | head -n1
|
|
58
|
+
}
|
|
59
|
+
|
|
50
60
|
RECREATE=false
|
|
51
61
|
while [ $# -gt 0 ]; do
|
|
52
62
|
case "$1" in
|
|
@@ -71,10 +81,35 @@ echo "Starting devcontainer for: $WORKSPACE_FOLDER"
|
|
|
71
81
|
UP_ARGS=(--workspace-folder "$WORKSPACE_FOLDER")
|
|
72
82
|
if [ "$RECREATE" = true ]; then
|
|
73
83
|
UP_ARGS+=(--remove-existing-container)
|
|
74
|
-
echo "Removing existing dev container so create-time settings (e.g.
|
|
84
|
+
echo "Removing existing dev container so create-time settings (e.g. runArgs) apply."
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
UP_OUTPUT="$(npx --yes "@devcontainers/cli@${CLI_VERSION}" up "${UP_ARGS[@]}")"
|
|
88
|
+
echo "$UP_OUTPUT"
|
|
89
|
+
|
|
90
|
+
CONTAINER_ID="$(echo "$UP_OUTPUT" | grep -oP '"containerId"\s*:\s*"\K[^"]+')" || true
|
|
91
|
+
if [ -z "$CONTAINER_ID" ]; then
|
|
92
|
+
CONTAINER_ID="$(docker ps --filter "label=devcontainer.local_folder=$WORKSPACE_FOLDER" --format '{{.ID}}' | head -n1)"
|
|
75
93
|
fi
|
|
76
94
|
|
|
77
|
-
|
|
95
|
+
CONTAINER_PORT="$(publish_container_port_from_devcontainer_json || true)"
|
|
96
|
+
if [ -n "$CONTAINER_ID" ]; then
|
|
97
|
+
if [ -n "$CONTAINER_PORT" ]; then
|
|
98
|
+
HOST_BINDING="$(docker port "$CONTAINER_ID" "${CONTAINER_PORT}/tcp" 2>/dev/null | head -n1)" || true
|
|
99
|
+
if [ -n "$HOST_BINDING" ]; then
|
|
100
|
+
echo ""
|
|
101
|
+
echo "Dev server available at: http://${HOST_BINDING}"
|
|
102
|
+
echo ""
|
|
103
|
+
else
|
|
104
|
+
echo "Warning: container is running but port ${CONTAINER_PORT}/tcp is not mapped." >&2
|
|
105
|
+
fi
|
|
106
|
+
else
|
|
107
|
+
echo "Warning: could not find a runArgs publish port (expected a quoted string like \"127.0.0.1::<port>\")." >&2
|
|
108
|
+
echo " Skipping docker port URL hint." >&2
|
|
109
|
+
fi
|
|
110
|
+
else
|
|
111
|
+
echo "Warning: could not resolve container ID; skipping port lookup." >&2
|
|
112
|
+
fi
|
|
78
113
|
|
|
79
114
|
echo "Dropping into container shell..."
|
|
80
115
|
# Resolve TERM to something the container's terminfo knows about.
|
|
@@ -83,4 +118,4 @@ echo "Dropping into container shell..."
|
|
|
83
118
|
if ! infocmp "${TERM:-xterm-256color}" &>/dev/null 2>&1; then
|
|
84
119
|
TERM=xterm-256color
|
|
85
120
|
fi
|
|
86
|
-
TERM="${TERM:-xterm-256color}" npx --yes @devcontainers/cli@${CLI_VERSION} exec --workspace-folder "$WORKSPACE_FOLDER" -- env TERM="${TERM:-xterm-256color}" COLORTERM=truecolor bash
|
|
121
|
+
TERM="${TERM:-xterm-256color}" npx --yes @devcontainers/cli@${CLI_VERSION} exec --workspace-folder "$WORKSPACE_FOLDER" -- env TERM="${TERM:-xterm-256color}" COLORTERM=truecolor bash
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Install workspace JS dependencies when package.json exists (non-fatal on failure).
|
|
3
|
+
|
|
4
|
+
main() {
|
|
5
|
+
[[ -f package.json ]] || return 0
|
|
6
|
+
local pm
|
|
7
|
+
pm=$(detect_package_manager)
|
|
8
|
+
install_dependencies "$pm" || true
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
detect_package_manager() {
|
|
12
|
+
local pm
|
|
13
|
+
if pm=$(detect_package_manager_from_lockfiles); then
|
|
14
|
+
echo "$pm"
|
|
15
|
+
return
|
|
16
|
+
fi
|
|
17
|
+
if pm=$(detect_package_manager_from_repo_markers); then
|
|
18
|
+
echo "$pm"
|
|
19
|
+
return
|
|
20
|
+
fi
|
|
21
|
+
if pm=$(detect_package_manager_from_package_json); then
|
|
22
|
+
echo "$pm"
|
|
23
|
+
return
|
|
24
|
+
fi
|
|
25
|
+
echo npm
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
detect_package_manager_from_lockfiles() {
|
|
29
|
+
if [[ -f pnpm-lock.yaml ]]; then
|
|
30
|
+
echo pnpm
|
|
31
|
+
return 0
|
|
32
|
+
fi
|
|
33
|
+
if [[ -f bun.lockb || -f bun.lock ]]; then
|
|
34
|
+
echo bun
|
|
35
|
+
return 0
|
|
36
|
+
fi
|
|
37
|
+
if [[ -f yarn.lock ]]; then
|
|
38
|
+
echo yarn
|
|
39
|
+
return 0
|
|
40
|
+
fi
|
|
41
|
+
if [[ -f package-lock.json ]]; then
|
|
42
|
+
echo npm
|
|
43
|
+
return 0
|
|
44
|
+
fi
|
|
45
|
+
return 1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
detect_package_manager_from_repo_markers() {
|
|
49
|
+
if [[ -f pnpm-workspace.yaml ]]; then
|
|
50
|
+
echo pnpm
|
|
51
|
+
return 0
|
|
52
|
+
fi
|
|
53
|
+
if [[ -f bunfig.toml ]]; then
|
|
54
|
+
echo bun
|
|
55
|
+
return 0
|
|
56
|
+
fi
|
|
57
|
+
if [[ -f .yarnrc.yml ]]; then
|
|
58
|
+
echo yarn
|
|
59
|
+
return 0
|
|
60
|
+
fi
|
|
61
|
+
return 1
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
detect_package_manager_from_package_json() {
|
|
65
|
+
[[ -f package.json ]] || return 1
|
|
66
|
+
node -e "
|
|
67
|
+
const p = require('./package.json');
|
|
68
|
+
const spec = p.packageManager;
|
|
69
|
+
if (!spec || typeof spec !== 'string') process.exit(1);
|
|
70
|
+
const name = spec.split('@')[0].trim();
|
|
71
|
+
if (!['pnpm', 'npm', 'yarn', 'bun'].includes(name)) process.exit(1);
|
|
72
|
+
console.log(name);
|
|
73
|
+
" 2>/dev/null || return 1
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
install_dependencies() {
|
|
77
|
+
local pm="$1"
|
|
78
|
+
case "$pm" in
|
|
79
|
+
pnpm) pnpm install ;;
|
|
80
|
+
npm) npm install ;;
|
|
81
|
+
yarn) yarn install ;;
|
|
82
|
+
bun) bun install ;;
|
|
83
|
+
*) npm install ;;
|
|
84
|
+
esac
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
main "$@"
|