Files
platform/scripts/provision-user-dirs.ts
pastilhasandClaude Opus 5 f5f509a99d scripts/setup is the initial install, nothing else
Two of the eight did not belong. cleanup-desktop.sh is the teardown — the inverse of an install, not part
of one. provision-user-dirs.ts runs per account at invite time, on a machine that is already set up.
Both are back at the top level, with their `../` derivations and usage strings put back.

What is left is what a fresh machine runs once: the two installers (setup.sh, setup_mac_light.sh), the
two things setup.sh calls (setup-dockers.sh, setup-desktop.sh), and the two files they deploy —
starship.toml, copied to ~/.config, and officer-set-display.sh, which setup-desktop.sh installs to
~/.local/bin as a login-time mode setter. The last one is not a setup script and does not read like one;
it is here because it is install payload, same as the toml, and setup-desktop.sh loads it by
`$(dirname $0)`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 04:05:06 +00:00

58 lines
2.4 KiB
TypeScript

// Create the per-user root under DATA_PATH for the given accounts.
//
// bun scripts/provision-user-dirs.ts a@b.com c@d.com
// DRY_RUN=1 bun scripts/provision-user-dirs.ts a@b.com
//
// 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
// caller already knows the email.
//
// This is the directory skeleton ONLY. It is deliberately not a revival of the old provision.ts, which
// also seeded shell rc files and wrote a generated CLAUDE.md + settings.json describing the user's
// Docker container. That architecture is gone. What survives from it is the useful part: a user has a
// root, and a home inside it.
//
// Idempotent — an existing directory is left exactly as it is, so re-running is safe.
import { mkdirSync, existsSync } from 'node:fs';
import { join } from 'node:path';
// 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
// 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';
const DRY_RUN = process.env.DRY_RUN === '1';
const emails = process.argv.slice(2).filter(Boolean);
if (!emails.length) {
console.error('Usage: bun scripts/provision-user-dirs.ts <email> [email...]');
process.exit(2);
}
// A stray argument would create a junk directory next to real user roots, and it would look like a
// user. Cheap to refuse.
const invalid = emails.filter((e) => !/^[^\s@/]+@[^\s@/]+\.[^\s@/]+$/.test(e));
if (invalid.length) {
console.error(`Not valid email addresses: ${invalid.join(', ')}`);
process.exit(2);
}
console.log(`DATA_PATH = ${DATA_PATH}`);
console.log(`${DRY_RUN ? 'Would provision' : 'Provisioning'} ${emails.length} user root(s)\n`);
for (const email of emails) {
const root = join(DATA_PATH, email);
console.log(`${email}${existsSync(root) ? '' : ' [new root]'}`);
for (const dir of USER_DIRS) {
const path = join(root, dir);
if (existsSync(path)) {
console.log(` · ${dir} (exists)`);
continue;
}
if (!DRY_RUN) mkdirSync(path, { recursive: true });
console.log(` ${DRY_RUN ? '+' : '✓'} ${dir}`);
}
console.log('');
}