Some checks failed
CI / Build & test (Node 24) (push) Has been cancelled
CI / Pack & boot smoke (Node 22) (push) Has been cancelled
CI / No em/en dashes (push) Has been cancelled
CI / Build & test (Node 22) (push) Has been cancelled
Deploy site (production) / build-and-deploy (push) Successful in 20s
Remplace les 547 tirets cadratins (U+2014) et demi-cadratins (U+2013) des fichiers versionnés par la ponctuation contextuelle adaptée (point médian, deux-points, virgule, parenthèses ; tiret simple pour les plages), sur 122 fichiers (appli, vitrine, doc, tests, workflows, scripts). Ajoute le job CI « lint-dashes » (git grep -P) qui échoue si un tiret cadratin/demi-cadratin réapparaît, hors logo binaire et captures brutes du terminal (fidélité des fixtures de détection de dialogue).
85 lines
3.6 KiB
TypeScript
85 lines
3.6 KiB
TypeScript
import { parseArgs } from 'node:util';
|
|
import { join } from 'node:path';
|
|
import { homedir } from 'node:os';
|
|
import { chmodSync, mkdirSync } from 'node:fs';
|
|
|
|
export interface Config {
|
|
port: number;
|
|
bind: string;
|
|
dbPath: string;
|
|
dataDir: string;
|
|
/** origins supplémentaires autorisées (ex. https://machine.tailnet.ts.net) */
|
|
allowedOrigins: string[];
|
|
printToken: boolean;
|
|
/** racine effective de l'install Claude (~/.claude par défaut, --claude-home, ou réglage claude_home). */
|
|
claudeHome: string;
|
|
/** true si --claude-home a été passé explicitement → a priorité sur le réglage claude_home. */
|
|
claudeHomeFromFlag: boolean;
|
|
/** ~/.claude/projects (transcripts JSONL) : surchargeable via --claude-home (tests). */
|
|
claudeProjectsDir: string;
|
|
/** ~/.claude/sessions (registre des sessions CLI vivantes). */
|
|
claudeSessionsDir: string;
|
|
/** sujet VAPID des notifications Web Push (mailto: ou URL). */
|
|
vapidContact: string;
|
|
/** découverte auto des repos au démarrage + périodique (désactivable via --no-discover). */
|
|
autoDiscover: boolean;
|
|
}
|
|
|
|
export function loadConfig(argv = process.argv.slice(2)): Config {
|
|
const { values } = parseArgs({
|
|
args: argv,
|
|
options: {
|
|
port: { type: 'string', default: '7317' },
|
|
bind: { type: 'string', default: '127.0.0.1' },
|
|
db: { type: 'string' },
|
|
'allow-origin': { type: 'string', multiple: true },
|
|
'print-token': { type: 'boolean', default: false },
|
|
'i-know-this-exposes-a-terminal': { type: 'boolean', default: false },
|
|
// racine de l'install Claude (~/.claude par défaut) : surchargée par les tests d'acceptation.
|
|
'claude-home': { type: 'string' },
|
|
// sujet VAPID des notifications push (contact requis par la spec Web Push).
|
|
'vapid-contact': { type: 'string' },
|
|
// désactive la découverte auto des repos (boot + périodique) : utilisé par les tests d'acceptation.
|
|
'no-discover': { type: 'boolean', default: false },
|
|
},
|
|
strict: true,
|
|
});
|
|
|
|
const bind = values.bind ?? '127.0.0.1';
|
|
const loopback = bind === '127.0.0.1' || bind === '::1' || bind === 'localhost';
|
|
if (!loopback && !values['i-know-this-exposes-a-terminal']) {
|
|
throw new Error(
|
|
`Refusing to bind to ${bind}: an Arboretum server is remote code execution by design.\n` +
|
|
`Use Tailscale Serve against the default 127.0.0.1 bind (recommended), or pass\n` +
|
|
`--i-know-this-exposes-a-terminal if you really know what you are doing.`,
|
|
);
|
|
}
|
|
|
|
const dataDir = join(process.env.XDG_DATA_HOME ?? join(homedir(), '.local', 'share'), 'arboretum');
|
|
mkdirSync(dataDir, { recursive: true });
|
|
// La DB contient des secrets (server_secret, clé privée VAPID, hashs de tokens) : le dossier de
|
|
// données ne doit jamais être lisible par d'autres utilisateurs du système. chmod best-effort
|
|
// (peut échouer sur certains FS Windows/montés ; le démarrage avertit alors sans bloquer).
|
|
try {
|
|
chmodSync(dataDir, 0o700);
|
|
} catch {
|
|
/* FS sans permissions POSIX : ignoré, cf. avertissement dans db.openDb */
|
|
}
|
|
const claudeHomeFlag = values['claude-home'];
|
|
const claudeHome = claudeHomeFlag ?? join(homedir(), '.claude');
|
|
return {
|
|
port: Number(values.port),
|
|
bind,
|
|
dbPath: values.db ?? join(dataDir, 'arboretum.db'),
|
|
dataDir,
|
|
allowedOrigins: values['allow-origin'] ?? [],
|
|
printToken: values['print-token'] ?? false,
|
|
claudeHome,
|
|
claudeHomeFromFlag: claudeHomeFlag !== undefined,
|
|
claudeProjectsDir: join(claudeHome, 'projects'),
|
|
claudeSessionsDir: join(claudeHome, 'sessions'),
|
|
vapidContact: values['vapid-contact'] ?? 'mailto:arboretum@localhost',
|
|
autoDiscover: !(values['no-discover'] ?? false),
|
|
};
|
|
}
|