- Réglages → Claude CLI : override du chemin du binaire `claude` (effet à la prochaine session, fallback `which claude`), diagnostic de détection, et override de la racine ~/.claude (effet au redémarrage). Validateurs stricts. - Push : notifie aussi sur le front busy→idle (session redevenue disponible). - Renomme l'état affiché idle → « disponible » / « available » (web EN/FR + VS Code) ; l'enum SessionActivity du protocole reste inchangé.
90 lines
3.3 KiB
TypeScript
90 lines
3.3 KiB
TypeScript
// Réglages CLI Claude (chemin du binaire + override ~/.claude) : validateurs + lecture/écriture DB.
|
|
import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
import { openDb, setSetting, type Db } from '../src/db/index.js';
|
|
import {
|
|
CLAUDE_BIN_PATH_KEY,
|
|
CLAUDE_HOME_KEY,
|
|
normalizeClaudeBinPath,
|
|
normalizeClaudeHome,
|
|
readClaudeBinPath,
|
|
readClaudeHome,
|
|
} from '../src/core/claude-settings.js';
|
|
|
|
let dir: string;
|
|
let execFile: string;
|
|
let plainFile: string;
|
|
let subDir: string;
|
|
|
|
beforeAll(() => {
|
|
dir = mkdtempSync(join(tmpdir(), 'arboretum-claude-settings-'));
|
|
execFile = join(dir, 'claude');
|
|
writeFileSync(execFile, '#!/bin/sh\n');
|
|
chmodSync(execFile, 0o755); // exécutable
|
|
plainFile = join(dir, 'notexec');
|
|
writeFileSync(plainFile, 'x');
|
|
chmodSync(plainFile, 0o644); // non exécutable
|
|
subDir = join(dir, 'home');
|
|
mkdirSync(subDir);
|
|
});
|
|
|
|
afterAll(() => rmSync(dir, { recursive: true, force: true }));
|
|
|
|
describe('normalizeClaudeBinPath', () => {
|
|
it('accepte un chemin absolu vers un fichier exécutable', () => {
|
|
expect(normalizeClaudeBinPath(execFile)).toBe(execFile);
|
|
});
|
|
it('"" = réinitialisation (auto-détection)', () => {
|
|
expect(normalizeClaudeBinPath('')).toBe('');
|
|
expect(normalizeClaudeBinPath(' ')).toBe('');
|
|
});
|
|
it('rejette un fichier non exécutable, un répertoire, un chemin relatif ou avec ".." (null)', () => {
|
|
expect(normalizeClaudeBinPath(plainFile)).toBeNull();
|
|
expect(normalizeClaudeBinPath(subDir)).toBeNull(); // répertoire, pas un fichier
|
|
expect(normalizeClaudeBinPath('relative/claude')).toBeNull();
|
|
expect(normalizeClaudeBinPath(join(dir, '..', 'x'))).toBeNull();
|
|
expect(normalizeClaudeBinPath(join(dir, 'missing'))).toBeNull();
|
|
expect(normalizeClaudeBinPath(42)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('normalizeClaudeHome', () => {
|
|
it('accepte un chemin absolu vers un répertoire existant', () => {
|
|
expect(normalizeClaudeHome(subDir)).toBe(subDir);
|
|
});
|
|
it('"" = réinitialisation (défaut)', () => {
|
|
expect(normalizeClaudeHome('')).toBe('');
|
|
});
|
|
it('rejette un fichier, un chemin relatif/inexistant (null)', () => {
|
|
expect(normalizeClaudeHome(execFile)).toBeNull(); // fichier, pas un répertoire
|
|
expect(normalizeClaudeHome('relative/.claude')).toBeNull();
|
|
expect(normalizeClaudeHome(join(dir, 'missing'))).toBeNull();
|
|
expect(normalizeClaudeHome(null)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe('readClaudeBinPath / readClaudeHome', () => {
|
|
let db: Db;
|
|
beforeAll(() => {
|
|
db = openDb(join(dir, 'settings.db'));
|
|
});
|
|
afterAll(() => db.close());
|
|
|
|
it('null quand non défini', () => {
|
|
expect(readClaudeBinPath(db)).toBeNull();
|
|
expect(readClaudeHome(db)).toBeNull();
|
|
});
|
|
it('lit la valeur stockée et traite "" stockée comme null', () => {
|
|
setSetting(db, CLAUDE_BIN_PATH_KEY, execFile);
|
|
setSetting(db, CLAUDE_HOME_KEY, subDir);
|
|
expect(readClaudeBinPath(db)).toBe(execFile);
|
|
expect(readClaudeHome(db)).toBe(subDir);
|
|
setSetting(db, CLAUDE_BIN_PATH_KEY, ''); // réinitialisé
|
|
setSetting(db, CLAUDE_HOME_KEY, '');
|
|
expect(readClaudeBinPath(db)).toBeNull();
|
|
expect(readClaudeHome(db)).toBeNull();
|
|
});
|
|
});
|