move host setup into scripts/setup/
scripts/ was holding two unrelated kinds of thing: install-this-machine, and run-this-occasionally. The eight installers now live in scripts/setup/; what stays at the top level is the build steps (gen-index, prebuild, build/) and the two maintenance scripts (reindex-music, rebuild-soulseek-tree). The move is not just a rename. Three of these derive the repo root from their own location: setup.sh:51 PROJECT_DIR="$(dirname "$SCRIPT_DIR")" setup_mac_light.sh:51 same cleanup-desktop.sh:134 ENV_FILE="$(dirname "$0")/../.env" Left alone, all three would now resolve to scripts/ — and nothing downstream complains. PROJECT_DIR is where .env is written, where `bun install`, `gen:index` and `db:push` run, and what pm2 is pointed at, so a fresh install would have quietly provisioned scripts/ and reported success. cleanup-desktop.sh fails the other way: it would find no .env, print "No .env — skipping", and leave the real VNC_PASSWORD in the real file. All three are now `../..` with a comment saying why the level matters. provision-user-dirs.ts imports data-path.ts relatively; that one tsgo caught. Also disambiguated `setup.sh` where it had become two files. app-store/templates/<name>/setup.sh is a per-sidecar installer with its own contract, and preflight.ts + docs/sidecar-app-store.md discussed both in the same paragraph. The host one is now spelled with its full path at those sites. Verified: bash -n on all six shell scripts, tsgo clean, os-user tests pass, both derivations resolve to the repo root, starship.toml still resolves from os-user-shell.ts, and provision-user-dirs.ts runs under DRY_RUN. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -52,7 +52,7 @@ the owner's OS user and can never be granted. Indirection there really is accide
|
|||||||
`'Unverified'` and `signin.ts` refuses anything else with a bare UNAUTHORIZED, which is the trap
|
`'Unverified'` and `signin.ts` refuses anything else with a bare UNAUTHORIZED, which is the trap
|
||||||
the hand-INSERT route fell into. The owner sets the password and reads it out; `passwordChangedAt`
|
the hand-INSERT route fell into. The owner sets the password and reads it out; `passwordChangedAt`
|
||||||
stays null. Directories come from the shared `provisionUserDirs`/`USER_DIRS` in `data-path.ts`,
|
stays null. Directories come from the shared `provisionUserDirs`/`USER_DIRS` in `data-path.ts`,
|
||||||
which `scripts/provision-user-dirs.ts` now imports rather than restating.
|
which `scripts/setup/provision-user-dirs.ts` now imports rather than restating.
|
||||||
|
|
||||||
- [ ] **Still no invite flow, and no password reset for a member.** The owner types the password and
|
- [ ] **Still no invite flow, and no password reset for a member.** The owner types the password and
|
||||||
tells the person, which means the owner knows it and the member cannot change it back if they
|
tells the person, which means the owner knows it and the member cannot change it back if they
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ test (`os-user.test.ts` → "does not pass the platform environment through").
|
|||||||
sudoers *policy* — `env_reset`, `env_keep`, `always_set_home` — and "which variables cross into a member's
|
sudoers *policy* — `env_reset`, `env_keep`, `always_set_home` — and "which variables cross into a member's
|
||||||
shell" must not depend on a config file someone may have edited.
|
shell" must not depend on a config file someone may have edited.
|
||||||
|
|
||||||
Root is available: `scripts/setup.sh` §4 installs `/etc/sudoers.d/officer-service` granting the service
|
Root is available: `scripts/setup/setup.sh` §4 installs `/etc/sudoers.d/officer-service` granting the service
|
||||||
user `NOPASSWD: ALL` on the full profile. The light profile deliberately skips it, so a light install that
|
user `NOPASSWD: ALL` on the full profile. The light profile deliberately skips it, so a light install that
|
||||||
wants OS users needs a **narrow** entry — `useradd`, `chown`, `setpriv` — which is better than the blanket
|
wants OS users needs a **narrow** entry — `useradd`, `chown`, `setpriv` — which is better than the blanket
|
||||||
rule anyway.
|
rule anyway.
|
||||||
|
|||||||
@@ -107,9 +107,13 @@ consequences, both wanted:
|
|||||||
|
|
||||||
### Docker is assumed, and nothing guarantees it
|
### Docker is assumed, and nothing guarantees it
|
||||||
|
|
||||||
Verified: **nothing in `scripts/` installs Docker, and nothing checks for it.** `setup.sh` calls
|
Verified: **nothing in `scripts/` installs Docker, and nothing checks for it.** The host installer
|
||||||
`setup-dockers.sh`, which invokes `docker compose` with no preflight, so a fresh host without Docker
|
`scripts/setup/setup.sh` calls `scripts/setup/setup-dockers.sh`, which invokes `docker compose` with no
|
||||||
fails partway through setup with a bare "command not found".
|
preflight, so a fresh host without Docker fails partway through setup with a bare "command not found".
|
||||||
|
|
||||||
|
(Not to be confused with the per-template `setup.sh` below — `app-store/templates/<name>/setup.sh` — which
|
||||||
|
is a different file with a different contract. The host one provisions the machine; a template one
|
||||||
|
provisions a single sidecar.)
|
||||||
|
|
||||||
That is the seam where this project's origin shows — it began as one person's own machine, provisioned
|
That is the seam where this project's origin shows — it began as one person's own machine, provisioned
|
||||||
by his own scripts, where Docker was simply always there.
|
by his own scripts, where Docker was simply always there.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Linux light profile — the platform without the self-hosted estate around it.
|
// Linux light profile — the platform without the self-hosted estate around it.
|
||||||
//
|
//
|
||||||
// For a machine that should run the file browser, the terminal and Claude/opencode chat, and nothing
|
// For a machine that should run the file browser, the terminal and Claude/opencode chat, and nothing
|
||||||
// else. Paired with `OFFICER_PROFILE=light bash scripts/setup.sh`, which installs only what these
|
// else. Paired with `OFFICER_PROFILE=light bash scripts/setup/setup.sh`, which installs only what these
|
||||||
// processes need: node, bun, ffmpeg, Postgres, pm2 and the two agent CLIs.
|
// processes need: node, bun, ffmpeg, Postgres, pm2 and the two agent CLIs.
|
||||||
//
|
//
|
||||||
// This is a subset of ecosystem.config.cjs, not a copy of it — see ecosystem.profile.cjs for why, and
|
// This is a subset of ecosystem.config.cjs, not a copy of it — see ecosystem.profile.cjs for why, and
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// macOS light profile — the same process set as the Linux light profile, on a laptop.
|
// macOS light profile — the same process set as the Linux light profile, on a laptop.
|
||||||
//
|
//
|
||||||
// Paired with scripts/setup_mac_light.sh. Runs the file browser, the terminal and Claude/opencode
|
// Paired with scripts/setup/setup_mac_light.sh. Runs the file browser, the terminal and Claude/opencode
|
||||||
// chat; nothing else.
|
// chat; nothing else.
|
||||||
//
|
//
|
||||||
// This is a subset of ecosystem.config.cjs, not a copy of it. That distinction is here because of this
|
// This is a subset of ecosystem.config.cjs, not a copy of it. That distinction is here because of this
|
||||||
|
|||||||
+1
-1
@@ -25,7 +25,7 @@
|
|||||||
"format": "{ git diff --name-only HEAD -- 'src/**/*.ts' 'src/**/*.tsx'; git ls-files --others --exclude-standard -- 'src/**/*.ts' 'src/**/*.tsx'; } | xargs -r prettier --write",
|
"format": "{ git diff --name-only HEAD -- 'src/**/*.ts' 'src/**/*.tsx'; git ls-files --others --exclude-standard -- 'src/**/*.ts' 'src/**/*.tsx'; } | xargs -r prettier --write",
|
||||||
"format:all": "prettier --write \"src/**/*.{ts,tsx}\"",
|
"format:all": "prettier --write \"src/**/*.{ts,tsx}\"",
|
||||||
"format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
|
"format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
|
||||||
"setup": "bash scripts/setup.sh"
|
"setup": "bash scripts/setup/setup.sh"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.2.41",
|
"@anthropic-ai/claude-agent-sdk": "^0.2.41",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ set -euo pipefail
|
|||||||
# their profile in it. Opt in rather than surprise someone.
|
# their profile in it. Opt in rather than surprise someone.
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# bash scripts/cleanup-desktop.sh [--purge-brave]
|
# bash scripts/setup/cleanup-desktop.sh [--purge-brave]
|
||||||
#
|
#
|
||||||
# Reboot afterwards: the GDM and GRUB changes are both boot-time.
|
# Reboot afterwards: the GDM and GRUB changes are both boot-time.
|
||||||
|
|
||||||
@@ -131,7 +131,9 @@ fi
|
|||||||
|
|
||||||
# --- Step 7: .env ---
|
# --- Step 7: .env ---
|
||||||
echo "[7/7] Cleaning .env..."
|
echo "[7/7] Cleaning .env..."
|
||||||
ENV_FILE="$(cd "$(dirname "$0")/.." && pwd)/.env"
|
# ../.. — this lives in scripts/setup/. A wrong level here is quiet in the other direction: the sed
|
||||||
|
# below simply finds no file, reports "No .env" and leaves the real VNC_PASSWORD in place.
|
||||||
|
ENV_FILE="$(cd "$(dirname "$0")/../.." && pwd)/.env"
|
||||||
if [ -f "$ENV_FILE" ]; then
|
if [ -f "$ENV_FILE" ]; then
|
||||||
sed -i '/^VNC_PASSWORD=/d; /^VNC_PORT=/d' "$ENV_FILE"
|
sed -i '/^VNC_PASSWORD=/d; /^VNC_PORT=/d' "$ENV_FILE"
|
||||||
echo " Removed VNC entries."
|
echo " Removed VNC entries."
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// Create the per-user root under DATA_PATH for the given accounts.
|
// Create the per-user root under DATA_PATH for the given accounts.
|
||||||
//
|
//
|
||||||
// bun scripts/provision-user-dirs.ts a@b.com c@d.com
|
// bun scripts/setup/provision-user-dirs.ts a@b.com c@d.com
|
||||||
// DRY_RUN=1 bun scripts/provision-user-dirs.ts a@b.com
|
// DRY_RUN=1 bun scripts/setup/provision-user-dirs.ts a@b.com
|
||||||
//
|
//
|
||||||
// Takes emails as arguments rather than reading the user table: the directory layout does not depend
|
// Takes emails as arguments rather than reading the user table: the directory layout does not depend
|
||||||
// on the database, and keeping the DB out means this runs with nothing else up. At invite time the
|
// on the database, and keeping the DB out means this runs with nothing else up. At invite time the
|
||||||
@@ -19,13 +19,13 @@ import { join } from 'node:path';
|
|||||||
// The list and DATA_PATH itself come from the platform rather than being restated here. The owner's
|
// The list and DATA_PATH itself come from the platform rather than being restated here. The owner's
|
||||||
// create-account handler provisions the same skeleton, and a script that drifted from it would produce
|
// create-account handler provisions the same skeleton, and a script that drifted from it would produce
|
||||||
// accounts that differ by how they were made. Importing data-path.ts pulls in no database and no server.
|
// accounts that differ by how they were made. Importing data-path.ts pulls in no database and no server.
|
||||||
import { DATA_PATH, USER_DIRS } from '../src/servers/data-path';
|
import { DATA_PATH, USER_DIRS } from '../../src/servers/data-path';
|
||||||
|
|
||||||
const DRY_RUN = process.env.DRY_RUN === '1';
|
const DRY_RUN = process.env.DRY_RUN === '1';
|
||||||
const emails = process.argv.slice(2).filter(Boolean);
|
const emails = process.argv.slice(2).filter(Boolean);
|
||||||
|
|
||||||
if (!emails.length) {
|
if (!emails.length) {
|
||||||
console.error('Usage: bun scripts/provision-user-dirs.ts <email> [email...]');
|
console.error('Usage: bun scripts/setup/provision-user-dirs.ts <email> [email...]');
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@ set -euo pipefail
|
|||||||
# capture an Xorg server, NOT a Wayland compositor — so we install the full GNOME desktop but force GDM
|
# capture an Xorg server, NOT a Wayland compositor — so we install the full GNOME desktop but force GDM
|
||||||
# onto the Xorg session (WaylandEnable=false). Auto-login is enabled so a user session owns :0 for the
|
# onto the Xorg session (WaylandEnable=false). Auto-login is enabled so a user session owns :0 for the
|
||||||
# mirror to attach to. Switching the display manager takes effect on the next reboot.
|
# mirror to attach to. Switching the display manager takes effect on the next reboot.
|
||||||
# Usage: ./scripts/setup-desktop.sh
|
# Usage: ./scripts/setup/setup-desktop.sh
|
||||||
|
|
||||||
echo "=== Officer Remote Desktop Setup (Ubuntu GNOME on Xorg) ==="
|
echo "=== Officer Remote Desktop Setup (Ubuntu GNOME on Xorg) ==="
|
||||||
echo ""
|
echo ""
|
||||||
@@ -4,8 +4,8 @@
|
|||||||
# Outputs parseable key=value lines to stdout; all prompts go to stderr.
|
# Outputs parseable key=value lines to stdout; all prompts go to stderr.
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# bash scripts/setup-dockers.sh
|
# bash scripts/setup/setup-dockers.sh
|
||||||
# eval "$(bash scripts/setup-dockers.sh)"
|
# eval "$(bash scripts/setup/setup-dockers.sh)"
|
||||||
#
|
#
|
||||||
# Environment overrides:
|
# Environment overrides:
|
||||||
# SETUP_DOCKER_SERVICES="1 2 3" — pre-select services (or "all"/"none")
|
# SETUP_DOCKER_SERVICES="1 2 3" — pre-select services (or "all"/"none")
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
# Run once on a fresh Ubuntu/Debian host before launching the server.
|
# Run once on a fresh Ubuntu/Debian host before launching the server.
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# bash scripts/setup.sh # full server install
|
# bash scripts/setup/setup.sh # full server install
|
||||||
# OFFICER_PROFILE=light bash scripts/setup.sh # light install
|
# OFFICER_PROFILE=light bash scripts/setup/setup.sh # light install
|
||||||
#
|
#
|
||||||
# PROFILES
|
# PROFILES
|
||||||
# full Everything: the self-hosted estate, the remote desktop, the music/audio stack, the shell
|
# full Everything: the self-hosted estate, the remote desktop, the music/audio stack, the shell
|
||||||
@@ -48,7 +48,10 @@ is_light() { [ "$OFFICER_PROFILE" = "light" ]; }
|
|||||||
if is_light; then ECOSYSTEM_FILE="ecosystem.light.config.cjs"; else ECOSYSTEM_FILE="ecosystem.config.cjs"; fi
|
if is_light; then ECOSYSTEM_FILE="ecosystem.light.config.cjs"; else ECOSYSTEM_FILE="ecosystem.config.cjs"; fi
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
# ../.. — this lives in scripts/setup/, so the repo root is two levels up, not one. Nothing here fails
|
||||||
|
# loudly if that is wrong: PROJECT_DIR is where .env is written, where `bun install` and `db:push` run and
|
||||||
|
# where pm2 is pointed, so an off-by-one level silently sets up scripts/ instead of the repo.
|
||||||
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
# Resolve the real user's home even when running under sudo
|
# Resolve the real user's home even when running under sudo
|
||||||
if [[ -n "${SUDO_USER:-}" ]]; then
|
if [[ -n "${SUDO_USER:-}" ]]; then
|
||||||
@@ -540,7 +543,7 @@ if [ ! -f "$STARSHIP_DEST" ]; then
|
|||||||
elif cmp -s "$SCRIPT_DIR/starship.toml" "$STARSHIP_DEST"; then
|
elif cmp -s "$SCRIPT_DIR/starship.toml" "$STARSHIP_DEST"; then
|
||||||
skip "starship config"
|
skip "starship config"
|
||||||
else
|
else
|
||||||
warn "starship config kept — yours differs (cp scripts/starship.toml ~/.config/ to take this one)"
|
warn "starship config kept — yours differs (cp scripts/setup/starship.toml ~/.config/ to take this one)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Officer — macOS laptop setup.
|
# Officer — macOS laptop setup.
|
||||||
#
|
#
|
||||||
# The barebones counterpart to scripts/setup.sh (which targets an Ubuntu/Debian server and is left
|
# The barebones counterpart to scripts/setup/setup.sh (which targets an Ubuntu/Debian server and is left
|
||||||
# alone). This installs only what a laptop workflow needs: the file browser, Claude/opencode chat,
|
# alone). This installs only what a laptop workflow needs: the file browser, Claude/opencode chat,
|
||||||
# and a terminal. No Go/Rust/cliamp/PulseAudio, no neovim, no shell dotfile stack, no VNC desktop,
|
# and a terminal. No Go/Rust/cliamp/PulseAudio, no neovim, no shell dotfile stack, no VNC desktop,
|
||||||
# no sudoers grant, no power-management changes.
|
# no sudoers grant, no power-management changes.
|
||||||
#
|
#
|
||||||
# EVERY STEP IS OPTIONAL. Each one prompts before doing anything, and can be preset non-interactively:
|
# EVERY STEP IS OPTIONAL. Each one prompts before doing anything, and can be preset non-interactively:
|
||||||
#
|
#
|
||||||
# SETUP_POSTGRES=0 SETUP_OPENCODE=0 bash scripts/setup_mac_light.sh
|
# SETUP_POSTGRES=0 SETUP_OPENCODE=0 bash scripts/setup/setup_mac_light.sh
|
||||||
#
|
#
|
||||||
# SETUP_PACKAGES brew node@22 / bun / ffmpeg SETUP_CLAUDE claude code CLI
|
# SETUP_PACKAGES brew node@22 / bun / ffmpeg SETUP_CLAUDE claude code CLI
|
||||||
# SETUP_POSTGRES brew postgresql@18 + createdb SETUP_OPENCODE opencode CLI
|
# SETUP_POSTGRES brew postgresql@18 + createdb SETUP_OPENCODE opencode CLI
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
# This script never calls sudo itself — everything lands under the Homebrew prefix or $HOME. Note
|
# This script never calls sudo itself — everything lands under the Homebrew prefix or $HOME. Note
|
||||||
# that Homebrew's own installer does ask for an administrator password on a fresh Mac.
|
# that Homebrew's own installer does ask for an administrator password on a fresh Mac.
|
||||||
#
|
#
|
||||||
# Usage: bash scripts/setup_mac_light.sh
|
# Usage: bash scripts/setup/setup_mac_light.sh
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -48,7 +48,10 @@ FAILURES=()
|
|||||||
note_failure() { FAILURES+=("$1"); fail "$1"; }
|
note_failure() { FAILURES+=("$1"); fail "$1"; }
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
# ../.. — this lives in scripts/setup/. See the note in setup.sh: PROJECT_DIR is where .env is written
|
||||||
|
# and where bun install, gen:index, db:push and pm2 are pointed, and none of them fails loudly on the
|
||||||
|
# wrong directory.
|
||||||
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
|
||||||
PG_FORMULA="postgresql@18"
|
PG_FORMULA="postgresql@18"
|
||||||
PG_DATABASE="officer_dev"
|
PG_DATABASE="officer_dev"
|
||||||
@@ -103,7 +106,7 @@ echo "════════════════════════
|
|||||||
step "Preflight"
|
step "Preflight"
|
||||||
|
|
||||||
if [ "$(uname -s)" != "Darwin" ]; then
|
if [ "$(uname -s)" != "Darwin" ]; then
|
||||||
fail "This script is macOS-only. On Linux use scripts/setup.sh."
|
fail "This script is macOS-only. On Linux use scripts/setup/setup.sh."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -532,5 +535,5 @@ echo " • Not run on macOS: VNC desktop, email sync, music indexer, cliamp aud
|
|||||||
echo " that front a container or an external service — vault, slskd, headscale, transmission,"
|
echo " that front a container or an external service — vault, slskd, headscale, transmission,"
|
||||||
echo " invoiceshelf, memos, photos, caldav, notify, wallet. See ecosystem.mac.light.config.cjs."
|
echo " invoiceshelf, memos, photos, caldav, notify, wallet. See ecosystem.mac.light.config.cjs."
|
||||||
echo " • Pin a specific Claude CLI with CLAUDE_BIN=/path/to/claude in .env if you need to"
|
echo " • Pin a specific Claude CLI with CLAUDE_BIN=/path/to/claude in .env if you need to"
|
||||||
echo " • Re-run any single step with e.g. SETUP_OPENCODE=1 bash scripts/setup_mac_light.sh"
|
echo " • Re-run any single step with e.g. SETUP_OPENCODE=1 bash scripts/setup/setup_mac_light.sh"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -9,9 +9,10 @@ import type { CatalogueEntry } from './catalogue';
|
|||||||
//
|
//
|
||||||
// ── What this deliberately does NOT do ──
|
// ── What this deliberately does NOT do ──
|
||||||
//
|
//
|
||||||
// It does not install anything. Today nothing in `scripts/` installs Docker either — `setup.sh` runs
|
// It does not install anything. Today nothing in `scripts/` installs Docker either — the host installer
|
||||||
// `setup-dockers.sh`, which invokes `docker compose` without ever checking it exists, so a fresh host
|
// `scripts/setup/setup.sh` runs `scripts/setup/setup-dockers.sh`, which invokes `docker compose` without
|
||||||
// without Docker fails partway through setup with a bare "command not found". That is a real gap, and
|
// ever checking it exists, so a fresh host without Docker fails partway through setup with a bare
|
||||||
|
// "command not found". That is a real gap, and
|
||||||
// the intended fix is a per-sidecar `setup.sh` that ensures its own dependencies — which is also the
|
// the intended fix is a per-sidecar `setup.sh` that ensures its own dependencies — which is also the
|
||||||
// shape a sidecar needs once it lives in its own repository and ships independently.
|
// shape a sidecar needs once it lives in its own repository and ships independently.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export const getOwnerHomeDir = (email: string): string => process.env.HOME_DIR ?
|
|||||||
// non-owner's sessions would run.
|
// non-owner's sessions would run.
|
||||||
//
|
//
|
||||||
// Single-sourced here rather than in the script that used to own the list, because there are now two
|
// Single-sourced here rather than in the script that used to own the list, because there are now two
|
||||||
// callers — `scripts/provision-user-dirs.ts` and the owner's create-account handler — and a skeleton
|
// callers — `scripts/setup/provision-user-dirs.ts` and the owner's create-account handler — and a skeleton
|
||||||
// that differs depending on how the account was made is a bug nobody would think to look for.
|
// that differs depending on how the account was made is a bug nobody would think to look for.
|
||||||
export const USER_DIRS = ['home', 'attachments', 'cache', 'dashboards', 'email_accounts', 'logs', 'sidecar'] as const;
|
export const USER_DIRS = ['home', 'attachments', 'cache', 'dashboards', 'email_accounts', 'logs', 'sidecar'] as const;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { osUserHome, runAs } from './os-user';
|
|||||||
// A single `/usr/local/bin/claude` would be less disk and one version to reason about, and the argument for
|
// A single `/usr/local/bin/claude` would be less disk and one version to reason about, and the argument for
|
||||||
// it is real: the private part of Claude is the credential in `~/.claude`, not the executable. It is still
|
// it is real: the private part of Claude is the credential in `~/.claude`, not the executable. It is still
|
||||||
// the wrong shape here. `claude` updates itself — that is why the owner's own install goes through
|
// the wrong shape here. `claude` updates itself — that is why the owner's own install goes through
|
||||||
// Anthropic's installer rather than npm (`scripts/setup.sh:853`) — and a root-owned binary is one a member
|
// Anthropic's installer rather than npm (`scripts/setup/setup.sh:861`) — and a root-owned binary is one a member
|
||||||
// cannot update, which turns "my agent is a version behind" into a request to the owner. Per-member also
|
// cannot update, which turns "my agent is a version behind" into a request to the owner. Per-member also
|
||||||
// means the account's agent keeps working exactly as the tool ships, with no platform-shaped exception to
|
// means the account's agent keeps working exactly as the tool ships, with no platform-shaped exception to
|
||||||
// explain. Same command the owner ran, run as them, in their home.
|
// explain. Same command the owner ran, run as them, in their home.
|
||||||
@@ -29,7 +29,7 @@ import { osUserHome, runAs } from './os-user';
|
|||||||
// report whether the credential has appeared, so the UI can render the one-line instruction instead of an
|
// report whether the credential has appeared, so the UI can render the one-line instruction instead of an
|
||||||
// agent that fails for reasons nobody can see.
|
// agent that fails for reasons nobody can see.
|
||||||
|
|
||||||
/** Anthropic's own installer — the same one `scripts/setup.sh` uses for the owner, chosen for auto-update. */
|
/** Anthropic's own installer — the same one `scripts/setup/setup.sh` uses for the owner, chosen for auto-update. */
|
||||||
const CLAUDE_INSTALL_URL = 'https://claude.ai/install.sh';
|
const CLAUDE_INSTALL_URL = 'https://claude.ai/install.sh';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { osUserHome } from './os-user';
|
|||||||
//
|
//
|
||||||
// ── What it is ──
|
// ── What it is ──
|
||||||
//
|
//
|
||||||
// `shell-skel/zshrc` → `~/.zshrc`, and the platform's own `scripts/starship.toml` → `~/.config/starship.toml`
|
// `shell-skel/zshrc` → `~/.zshrc`, and the platform's own `scripts/setup/starship.toml` → `~/.config/starship.toml`
|
||||||
// so a member's prompt is the same one the owner's install deploys. That file is the single source for both:
|
// so a member's prompt is the same one the owner's install deploys. That file is the single source for both:
|
||||||
// setup.sh copies it for the owner and this copies it for everybody else, so the two cannot drift.
|
// setup.sh copies it for the owner and this copies it for everybody else, so the two cannot drift.
|
||||||
//
|
//
|
||||||
@@ -31,7 +31,7 @@ import { osUserHome } from './os-user';
|
|||||||
/** Where the templates live, relative to this file. */
|
/** Where the templates live, relative to this file. */
|
||||||
const SKEL_DIR = join(import.meta.dir, 'shell-skel');
|
const SKEL_DIR = join(import.meta.dir, 'shell-skel');
|
||||||
/** The prompt config the owner's own install uses — one file, both audiences. */
|
/** The prompt config the owner's own install uses — one file, both audiences. */
|
||||||
const STARSHIP_SRC = join(import.meta.dir, '../../scripts/starship.toml');
|
const STARSHIP_SRC = join(import.meta.dir, '../../scripts/setup/starship.toml');
|
||||||
|
|
||||||
type SudoResult = { ok: boolean; out: string };
|
type SudoResult = { ok: boolean; out: string };
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user