totopo 3.7.0 → 3.8.1

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 CHANGED
@@ -70,11 +70,11 @@ A few key concepts:
70
70
 
71
71
  ### `totopo.yaml`
72
72
 
73
- The config is minimal — four fields:
73
+ The config is minimal — only `workspace_id` is required; the rest are optional:
74
74
 
75
- - **`workspace_id`** — unique slug for container naming and cache directory
76
- - **`profiles`** — Dockerfile image variants (see [Profiles](#profiles))
77
- - **`shadow_paths`** — gitignore-style patterns hidden from agents (see [Shadow Paths](#shadow-paths))
75
+ - **`workspace_id`** *(required)* — unique slug for container naming and cache directory
76
+ - **`profiles`** *(optional)* — Dockerfile image variants (see [Profiles](#profiles))
77
+ - **`shadow_paths`** *(optional)* — gitignore-style patterns hidden from agents (see [Shadow Paths](#shadow-paths))
78
78
  - **`env_file`** *(optional)* — path to env file injected at runtime (see [Environment Variables](#environment-variables))
79
79
 
80
80
  On every run, totopo shows the workspace menu:
@@ -50,6 +50,7 @@ export const BAKED_TEMPLATE_FILES = [
50
50
  "claude-statusline.sh",
51
51
  "git-readonly-wrapper.mjs",
52
52
  "npmrc",
53
+ "pnpm-config.yaml",
53
54
  "runtime-constants.mjs",
54
55
  "startup-git-mode.mjs",
55
56
  "startup.mjs",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "totopo",
3
- "version": "3.7.0",
3
+ "version": "3.8.1",
4
4
  "description": "Run AI coding agents safely in your local codebase",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,16 @@
8
8
  # dockerfile_hook in totopo.yaml profiles.
9
9
  # =============================================================================
10
10
 
11
- FROM debian:bookworm-slim
11
+ # ---------------------------------------------------------------------------
12
+ # Version pinning policy
13
+ # Infra tools whose major versions can change behavior are pinned exact so that
14
+ # fresh and --no-cache builds stay reproducible; bumping a pin edits this file,
15
+ # busts the build hash, and auto-prompts a rebuild. Deliberately left floating:
16
+ # apt packages (pinned by the Debian trixie release), Node (major-pinned via
17
+ # setup_24.x; minors carry security fixes), and the AI CLIs (always latest).
18
+ # ---------------------------------------------------------------------------
19
+
20
+ FROM debian:trixie-slim
12
21
  LABEL totopo.managed=true
13
22
 
14
23
  # Enable 24-bit color support for AI CLIs (suppresses color upgrade prompts)
@@ -24,8 +33,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
24
33
  build-essential pkg-config libssl-dev \
25
34
  # Utilities
26
35
  jq unzip zip tree htop procps lsb-release gnupg ca-certificates sox file bubblewrap \
27
- # Modern search/navigation tools
28
- ripgrep fzf \
36
+ # Modern search/navigation tools (fd-find installs the binary as 'fdfind'; symlinked to 'fd' below)
37
+ ripgrep fzf fd-find \
29
38
  # Database clients
30
39
  sqlite3 postgresql-client default-mysql-client redis-tools \
31
40
  # Python (needed for build scripts and as a light default)
@@ -33,19 +42,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
33
42
  && rm -rf /var/lib/apt/lists/*
34
43
 
35
44
  # ---------------------------------------------------------------------------
36
- # Layer 2 — fd (GitHub release)
45
+ # Layer 2 — fd (from apt fd-find; Debian names the binary 'fdfind')
46
+ # Symlink to 'fd' so the tool is callable by its upstream name.
37
47
  # ---------------------------------------------------------------------------
38
- RUN ARCH=$(dpkg --print-architecture) && \
39
- FD_VERSION=$(curl -fsSL https://api.github.com/repos/sharkdp/fd/releases/latest \
40
- | python3 -c "import sys,json; print(json.load(sys.stdin)['tag_name'][1:])") && \
41
- curl -fsSL "https://github.com/sharkdp/fd/releases/download/v${FD_VERSION}/fd_${FD_VERSION}_${ARCH}.deb" \
42
- -o /tmp/fd.deb && dpkg -i /tmp/fd.deb && rm /tmp/fd.deb
48
+ RUN ln -sf "$(command -v fdfind)" /usr/local/bin/fd
43
49
 
44
50
  # ---------------------------------------------------------------------------
45
- # Layer 3 — yq (GitHub release)
51
+ # Layer 3 — yq (GitHub release, pinned)
46
52
  # ---------------------------------------------------------------------------
47
53
  RUN ARCH=$(dpkg --print-architecture) && \
48
- curl -fsSL "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}" \
54
+ curl -fsSL "https://github.com/mikefarah/yq/releases/download/v4.53.3/yq_linux_${ARCH}" \
49
55
  -o /usr/local/bin/yq && chmod +x /usr/local/bin/yq
50
56
 
51
57
  # ---------------------------------------------------------------------------
@@ -59,9 +65,10 @@ RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
59
65
  apt-get update && apt-get install -y gh && rm -rf /var/lib/apt/lists/*
60
66
 
61
67
  # ---------------------------------------------------------------------------
62
- # Layer 5 — Node.js LTS (via NodeSource)
68
+ # Layer 5 — Node.js 24 LTS (via NodeSource)
69
+ # Trixie's apt nodejs is 20.x; NodeSource is pinned to the current Active LTS (24.x).
63
70
  # ---------------------------------------------------------------------------
64
- RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \
71
+ RUN curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && \
65
72
  apt-get install -y nodejs && rm -rf /var/lib/apt/lists/*
66
73
 
67
74
  # ---------------------------------------------------------------------------
@@ -71,10 +78,13 @@ RUN git config --system protocol.allow never && \
71
78
  git config --system protocol.file.allow always
72
79
 
73
80
  # ---------------------------------------------------------------------------
74
- # Layer 7 — Global npm tools (AI CLIs)
81
+ # Layer 7 — Global npm tools (pnpm pinned; AI CLIs always latest)
82
+ # pnpm is pinned exact: pnpm 11 changed where global settings are read from
83
+ # (~/.config/pnpm/config.yaml, no longer ~/.npmrc), so an unpinned major bump
84
+ # can silently break the baked store-dir config.
75
85
  # ---------------------------------------------------------------------------
76
86
  RUN npm install -g \
77
- pnpm \
87
+ pnpm@11.6.0 \
78
88
  opencode-ai \
79
89
  @anthropic-ai/claude-code \
80
90
  @openai/codex \
@@ -85,18 +95,20 @@ RUN npm install -g \
85
95
  # ---------------------------------------------------------------------------
86
96
  RUN groupadd --gid 1001 devuser && \
87
97
  useradd --uid 1001 --gid devuser --shell /bin/bash --create-home devuser && \
88
- mkdir -p /home/devuser/.local/state /home/devuser/.local/share /home/devuser/.local/share/pnpm /home/devuser/.local/bin && \
98
+ mkdir -p /home/devuser/.local/state /home/devuser/.local/share /home/devuser/.local/share/pnpm /home/devuser/.local/bin /home/devuser/.config/pnpm && \
89
99
  date -u +"%Y-%m-%dT%H:%M:%S.000Z" > /home/devuser/.ai-cli-updated && \
90
100
  chown -R devuser:devuser /home/devuser
91
101
 
92
102
  # ---------------------------------------------------------------------------
93
- # Layer 9 — Bake startup script + git mode helper + shared constants into image
103
+ # Layer 9 — Bake startup script + git mode helper + shared constants + pnpm config into image
104
+ # pnpm 11+ reads settings from ~/.config/pnpm/config.yaml; ~/.npmrc covers anyone pinning pnpm <= 10.
94
105
  # ---------------------------------------------------------------------------
95
106
  COPY npmrc /home/devuser/.npmrc
107
+ COPY pnpm-config.yaml /home/devuser/.config/pnpm/config.yaml
96
108
  COPY startup.mjs /home/devuser/startup.mjs
97
109
  COPY startup-git-mode.mjs /home/devuser/startup-git-mode.mjs
98
110
  COPY runtime-constants.mjs /home/devuser/runtime-constants.mjs
99
- RUN chown devuser:devuser /home/devuser/.npmrc /home/devuser/startup.mjs /home/devuser/startup-git-mode.mjs /home/devuser/runtime-constants.mjs
111
+ RUN chown devuser:devuser /home/devuser/.npmrc /home/devuser/.config/pnpm/config.yaml /home/devuser/startup.mjs /home/devuser/startup-git-mode.mjs /home/devuser/runtime-constants.mjs
100
112
 
101
113
  # ---------------------------------------------------------------------------
102
114
  # Layer 10 — Bake git read-only wrapper into image
@@ -0,0 +1,9 @@
1
+ # pnpm global config. pnpm 11+ reads its settings from here (~/.config/pnpm/config.yaml),
2
+ # no longer from ~/.npmrc. Keys are camelCase, unlike the kebab-case equivalents in .npmrc.
3
+ #
4
+ # storeDir pins the global store onto a bind-mounted, same-device cache so pnpm never falls back
5
+ # to creating a .pnpm-store inside the mounted /workspace. packageImportMethod=copy avoids
6
+ # cross-filesystem hardlink failures. The matching ~/.npmrc keeps this working for anyone who
7
+ # pins an older pnpm via packageManager (pnpm <= 10 still reads .npmrc).
8
+ storeDir: /home/devuser/.local/share/pnpm/store
9
+ packageImportMethod: copy