devs-common 5.0.1__tar.gz → 5.0.3__tar.gz

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 (59) hide show
  1. {devs_common-5.0.1 → devs_common-5.0.3}/PKG-INFO +1 -1
  2. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/core/container.py +26 -1
  3. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/Dockerfile +2 -3
  4. devs_common-5.0.3/devs_common/templates/extensions/devs-bridge-drop.vsix +0 -0
  5. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/post-create-wrapper.sh +11 -0
  6. devs_common-5.0.3/devs_common/templates/scripts/run-autoexec.sh +30 -0
  7. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/utils/devcontainer.py +24 -2
  8. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/utils/docker_client.py +36 -6
  9. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common.egg-info/PKG-INFO +1 -1
  10. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common.egg-info/SOURCES.txt +1 -0
  11. {devs_common-5.0.1 → devs_common-5.0.3}/pyproject.toml +1 -1
  12. devs_common-5.0.1/devs_common/templates/extensions/devs-bridge-drop.vsix +0 -0
  13. {devs_common-5.0.1 → devs_common-5.0.3}/LICENSE +0 -0
  14. {devs_common-5.0.1 → devs_common-5.0.3}/README.md +0 -0
  15. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/__init__.py +0 -0
  16. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/config.py +0 -0
  17. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/core/__init__.py +0 -0
  18. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/core/project.py +0 -0
  19. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/core/workspace.py +0 -0
  20. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/devs_config.py +0 -0
  21. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/exceptions.py +0 -0
  22. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/README-vscode-settings.md +0 -0
  23. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/devcontainer.json +0 -0
  24. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/extensions/README.md +0 -0
  25. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/extensions/install.sh +0 -0
  26. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/machine-settings.json +0 -0
  27. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/machine-settings.tmux.json +0 -0
  28. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/register-vscode-extensions.js +0 -0
  29. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/copy-ssh.sh +0 -0
  30. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/install-bridge-drop.sh +0 -0
  31. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/post-start.sh +0 -0
  32. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/python-venv-integration.sh +0 -0
  33. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/screenshot-webapp.sh +0 -0
  34. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/setup-vscode-settings.sh +0 -0
  35. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/setup-workspace.sh +0 -0
  36. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/start-tailscale.sh +0 -0
  37. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/start-tunnel.sh +0 -0
  38. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/ts.sh +0 -0
  39. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/tunnel-status.sh +0 -0
  40. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/scripts/webapp-screenshot.py +0 -0
  41. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/sudo-scripts/init-firewall.sh +0 -0
  42. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/sudo-scripts/setup-devs-env.sh +0 -0
  43. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/sudo-scripts/setup-magicdns.sh +0 -0
  44. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/sudo-scripts/setup-vscode-cache.sh +0 -0
  45. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/sudo-scripts/start-services.sh +0 -0
  46. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/sudo-scripts/start-tailscaled.sh +0 -0
  47. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/sudo-scripts/ts-cli.sh +0 -0
  48. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/templates/vscode-settings-reference.md +0 -0
  49. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/utils/__init__.py +0 -0
  50. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/utils/config_hash.py +0 -0
  51. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/utils/console.py +0 -0
  52. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/utils/devcontainer_template.py +0 -0
  53. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/utils/file_utils.py +0 -0
  54. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/utils/git_utils.py +0 -0
  55. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common/utils/repo_cache.py +0 -0
  56. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common.egg-info/dependency_links.txt +0 -0
  57. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common.egg-info/requires.txt +0 -0
  58. {devs_common-5.0.1 → devs_common-5.0.3}/devs_common.egg-info/top_level.txt +0 -0
  59. {devs_common-5.0.1 → devs_common-5.0.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devs-common
3
- Version: 5.0.1
3
+ Version: 5.0.3
4
4
  Summary: Shared utilities for devs package ecosystem
5
5
  Author: Dan Lester
6
6
  License-Expression: MIT
@@ -433,9 +433,34 @@ class ContainerManager:
433
433
  tailscaled and the tailnet node stay down, and VS Code settings aren't
434
434
  re-deployed. The script is idempotent, so running it again is harmless. Never
435
435
  raises: a container without the devs template simply has no such script.
436
+
437
+ The hook's identity env (``DEVS_PROJECT_NAME``/``DEVCONTAINER_NAME``) comes from
438
+ devcontainer.json ``remoteEnv``, which only the devcontainer CLI injects — a raw
439
+ exec sees neither. Without them start-tailscale.sh falls through to its
440
+ ``devcontainer`` default and the node rejoins the tailnet as ``devs-devcontainer``
441
+ (then clash-suffixed ``-1``, ``-2``…) instead of ``devs-<project>-<dev>`` — so
442
+ every name anyone SSHes to breaks on each host reboot. Re-derive them from the
443
+ labels set at creation, which are the container's own record of that identity.
436
444
  """
445
+ environment = {}
446
+ try:
447
+ labels = self.docker.get_container_labels(container_name)
448
+ project = labels.get("devs.project", "")
449
+ dev = labels.get("devs.dev", "")
450
+ if project and dev:
451
+ environment = {
452
+ "DEVS_PROJECT_NAME": project,
453
+ "DEVCONTAINER_NAME": dev,
454
+ }
455
+ except Exception:
456
+ pass # fall back to the hook's own defaults
457
+
437
458
  try:
438
- self.docker.exec_command(container_name, "/usr/local/bin/post-start.sh")
459
+ self.docker.exec_command(
460
+ container_name,
461
+ "/usr/local/bin/post-start.sh",
462
+ environment=environment or None,
463
+ )
439
464
  except Exception:
440
465
  pass # not a devs-template container / exec unavailable
441
466
 
@@ -186,8 +186,8 @@ RUN for shell_rc in /home/node/.zshrc /home/node/.bashrc; do \
186
186
  echo "export CODEX_CONFIG_HOME=\"/home/node/codexconfig\"" >> "$shell_rc" && \
187
187
  echo "export PATH=\"/home/node/.local/bin:\$PATH\"" >> "$shell_rc" && \
188
188
  echo "alias claude=\"claude --dangerously-skip-permissions\"" >> "$shell_rc" && \
189
- echo "alias codex=\"/usr/local/share/npm-global/bin/codex --dangerously-bypass-approvals-and-sandbox\"" >> "$shell_rc" && \
190
- echo "alias codex-normal=\"/usr/local/share/npm-global/bin/codex\"" >> "$shell_rc" && \
189
+ echo "alias codex=\"/usr/local/share/npm-global/bin/codex -c check_for_update_on_startup=false --dangerously-bypass-approvals-and-sandbox\"" >> "$shell_rc" && \
190
+ echo "alias codex-normal=\"/usr/local/share/npm-global/bin/codex -c check_for_update_on_startup=false\"" >> "$shell_rc" && \
191
191
  echo "" >> "$shell_rc" && \
192
192
  echo "# Auto-activate Python venv if it exists" >> "$shell_rc" && \
193
193
  echo "if [ -f /home/node/.devs-venv/workspace-venv/bin/activate ]; then" >> "$shell_rc" && \
@@ -234,4 +234,3 @@ RUN echo "DEBUG: Files that need sudo:" && ls -la /tmp/sudo-scripts-list/ && \
234
234
  rm -rf /tmp/sudo-scripts-list
235
235
 
236
236
  USER node
237
-
@@ -34,12 +34,23 @@ run_step() {
34
34
  # Run each step with error handling
35
35
  run_step "setup-vscode-cache" "sudo /usr/local/bin/setup-vscode-cache.sh"
36
36
  run_step "setup-devs-env.sh" "/usr/local/bin/setup-devs-env.sh"
37
+ run_step "run-autoexec.sh" "/usr/local/bin/run-autoexec.sh"
37
38
  #run_step "init-firewall.sh" "sudo /usr/local/bin/init-firewall.sh"
38
39
  run_step "setup-workspace.sh" "/usr/local/bin/setup-workspace.sh"
39
40
  run_step "start-services.sh" "sudo /usr/local/bin/start-services.sh"
40
41
  # Optional: join the tailnet + serve a port. Non-fatal — no auth key => no-op.
41
42
  run_step "start-tailscale.sh" "/usr/local/bin/start-tailscale.sh" || true
42
43
 
44
+ # setup-devs-env.sh runs through run_step in a subshell, so variables it exports
45
+ # do not reach this wrapper. Load the mounted environment here as well so GH_TOKEN
46
+ # is available while gh configures git's credential helper.
47
+ if [ -f /home/node/.devs-env/.env ]; then
48
+ set -a
49
+ # shellcheck disable=SC1091 -- this file is supplied by the devs bind mount
50
+ source /home/node/.devs-env/.env
51
+ set +a
52
+ fi
53
+
43
54
  # GitHub auth setup is optional, so handle it separately
44
55
  echo "📋 Running gh auth setup-git..."
45
56
  if output=$(gh auth setup-git 2>&1); then
@@ -0,0 +1,30 @@
1
+ #!/bin/bash
2
+ # Run optional, user-supplied startup hooks from the mounted devs environment.
3
+ # The directory's presence is the opt-in; hooks run in lexical filename order.
4
+ set -uo pipefail
5
+
6
+ hooks_dir="${DEVS_AUTOEXEC_DIR:-/home/node/.devs-env/autoexec}"
7
+ [ -d "$hooks_dir" ] || exit 0
8
+
9
+ status=0
10
+ found=0
11
+ for hook in "$hooks_dir"/*; do
12
+ [ -f "$hook" ] || continue
13
+ [ -x "$hook" ] || {
14
+ echo "ℹ️ Skipping non-executable autoexec hook: $(basename "$hook")"
15
+ continue
16
+ }
17
+
18
+ found=1
19
+ echo "📋 Running autoexec hook: $(basename "$hook")"
20
+ if "$hook"; then
21
+ echo "✅ Autoexec hook completed: $(basename "$hook")"
22
+ else
23
+ hook_status=$?
24
+ echo "⚠️ Autoexec hook failed ($hook_status): $(basename "$hook")"
25
+ status=1
26
+ fi
27
+ done
28
+
29
+ [ "$found" -eq 0 ] || echo "🏁 Autoexec hooks finished"
30
+ exit "$status"
@@ -1,7 +1,9 @@
1
1
  """DevContainer CLI wrapper utilities."""
2
2
 
3
+ import json
3
4
  import os
4
5
  import re
6
+ import socket
5
7
  import sys
6
8
  import subprocess
7
9
  from pathlib import Path
@@ -44,8 +46,8 @@ def prepare_devcontainer_environment(
44
46
  env = os.environ.copy()
45
47
 
46
48
  # Core devcontainer environment variables
47
- # IMPORTANT: In live mode, we must use the actual host folder name (e.g. "workstuff")
48
- # instead of our constructed name (e.g. "workstuffai-workstuffapp-dan") because
49
+ # IMPORTANT: In live mode, we must use the actual host folder name (e.g. "devs")
50
+ # instead of our constructed name (e.g. "ideonate-devs-sally") because
49
51
  # the devcontainer CLI directly mounts the host folder and preserves its name.
50
52
  # The container will have /workspaces/<host-folder-name>, not /workspaces/<constructed-name>
51
53
  workspace_folder_name = workspace_folder.name if live else container_workspace_name
@@ -80,6 +82,7 @@ def prepare_devcontainer_environment(
80
82
  bridge_mount_path = Path.home() / '.devs' / 'bridge' / f"{project_name}-{dev_name}"
81
83
  bridge_mount_path.mkdir(parents=True, exist_ok=True)
82
84
  env['DEVS_BRIDGE_MOUNT_PATH'] = str(bridge_mount_path)
85
+ write_bridge_info(bridge_mount_path)
83
86
 
84
87
  # Pass debug mode to container scripts
85
88
  if debug:
@@ -104,6 +107,25 @@ def prepare_devcontainer_environment(
104
107
  return env
105
108
 
106
109
 
110
+ BRIDGE_INFO_FILENAME = '.devs-bridge.json'
111
+
112
+
113
+ def write_bridge_info(bridge_mount_path: Path) -> None:
114
+ """Record the bridge's host-side location inside the bridge itself.
115
+
116
+ The bridge-drop extension shows the host path for each dropped file. It
117
+ reads DEVS_BRIDGE_MOUNT_PATH when set, but that arrives via remoteEnv, which
118
+ only the Dev Containers extension applies — a Remote-SSH session straight
119
+ into the container never sees it. The bridge dir is mounted in the
120
+ container regardless of how VS Code connects, so the info lives there too.
121
+ """
122
+ info = {'host_path': str(bridge_mount_path), 'hostname': socket.gethostname()}
123
+ try:
124
+ (bridge_mount_path / BRIDGE_INFO_FILENAME).write_text(json.dumps(info, indent=2) + '\n')
125
+ except OSError as e:
126
+ console.print(f"[yellow]Warning: could not write bridge info: {e}[/yellow]")
127
+
128
+
107
129
  def parse_docker_error(error_output: str) -> Tuple[Optional[str], Optional[str]]:
108
130
  """Parse Docker error output for specific error patterns.
109
131
 
@@ -170,6 +170,25 @@ class DockerClient:
170
170
  except DockerException as e:
171
171
  raise DockerError(f"Error finding containers by labels: {e}")
172
172
 
173
+ def get_container_labels(self, name: str) -> Dict[str, str]:
174
+ """Get a single container's labels.
175
+
176
+ Args:
177
+ name: Container name or id
178
+
179
+ Returns:
180
+ The container's label dictionary
181
+
182
+ Raises:
183
+ DockerError: If the container is missing or inspection fails
184
+ """
185
+ try:
186
+ return self.client.containers.get(name).labels or {}
187
+ except NotFound:
188
+ raise DockerError(f"Container {name} not found")
189
+ except DockerException as e:
190
+ raise DockerError(f"Error inspecting container {name}: {e}")
191
+
173
192
  def rename_container(self, old_name: str, new_name: str) -> None:
174
193
  """Rename a container.
175
194
 
@@ -188,26 +207,37 @@ class DockerClient:
188
207
  except DockerException as e:
189
208
  raise DockerError(f"Error renaming container {old_name} to {new_name}: {e}")
190
209
 
191
- def exec_command(self, container_name: str, command: str, workdir: Optional[str] = None) -> bool:
210
+ def exec_command(
211
+ self,
212
+ container_name: str,
213
+ command: str,
214
+ workdir: Optional[str] = None,
215
+ environment: Optional[Dict[str, str]] = None,
216
+ ) -> bool:
192
217
  """Execute a command in a container.
193
-
218
+
194
219
  Args:
195
220
  container_name: Container name
196
221
  command: Command to execute
197
222
  workdir: Working directory for command
198
-
223
+ environment: Extra env vars for this exec only. A raw exec inherits the
224
+ image's baked-in env but NOT devcontainer.json ``remoteEnv``, which the
225
+ devcontainer CLI injects per-exec — pass anything the command needs from
226
+ there explicitly.
227
+
199
228
  Returns:
200
229
  True if command succeeded
201
-
230
+
202
231
  Raises:
203
232
  DockerError: If execution fails
204
233
  """
205
234
  try:
206
235
  container = self.client.containers.get(container_name)
207
-
236
+
208
237
  exec_result = container.exec_run(
209
- command,
238
+ command,
210
239
  workdir=workdir,
240
+ environment=environment,
211
241
  tty=False,
212
242
  stream=False
213
243
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devs-common
3
- Version: 5.0.1
3
+ Version: 5.0.3
4
4
  Summary: Shared utilities for devs package ecosystem
5
5
  Author: Dan Lester
6
6
  License-Expression: MIT
@@ -29,6 +29,7 @@ devs_common/templates/scripts/install-bridge-drop.sh
29
29
  devs_common/templates/scripts/post-create-wrapper.sh
30
30
  devs_common/templates/scripts/post-start.sh
31
31
  devs_common/templates/scripts/python-venv-integration.sh
32
+ devs_common/templates/scripts/run-autoexec.sh
32
33
  devs_common/templates/scripts/screenshot-webapp.sh
33
34
  devs_common/templates/scripts/setup-vscode-settings.sh
34
35
  devs_common/templates/scripts/setup-workspace.sh
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "devs-common"
7
- version = "5.0.1"
7
+ version = "5.0.3"
8
8
  description = "Shared utilities for devs package ecosystem"
9
9
  authors = [
10
10
  {name = "Dan Lester"},
File without changes
File without changes
File without changes