v2: make v2 the main entry point, move v1 to src/v1/
- Move all v1 files (index, router, container-runner, db, ipc, types, logger, channels/registry, and all utilities) to src/v1/ as a fully self-contained archive with no shared dependencies - Rename v2 files to remove -v2 suffix (index-v2.ts → index.ts, etc.) - Update all imports across v2 source, tests, and setup files - Migrate shared utilities (config, env, container-runtime, mount-security, timezone, group-folder) from pino logger to v2 log module - Migrate setup/ files from logger to log with argument order swap - Container agent-runner: move v1 entry to v1/, rename v2 to index.ts - Update setup skill to offer all 13 v2 channels - Install all Chat SDK adapter packages - dist/index.js now runs v2; dist/v1/index.js runs v1 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
44
src/v1/group-folder.ts
Normal file
44
src/v1/group-folder.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import path from 'path';
|
||||
|
||||
import { DATA_DIR, GROUPS_DIR } from './config.js';
|
||||
|
||||
const GROUP_FOLDER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
|
||||
const RESERVED_FOLDERS = new Set(['global']);
|
||||
|
||||
export function isValidGroupFolder(folder: string): boolean {
|
||||
if (!folder) return false;
|
||||
if (folder !== folder.trim()) return false;
|
||||
if (!GROUP_FOLDER_PATTERN.test(folder)) return false;
|
||||
if (folder.includes('/') || folder.includes('\\')) return false;
|
||||
if (folder.includes('..')) return false;
|
||||
if (RESERVED_FOLDERS.has(folder.toLowerCase())) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function assertValidGroupFolder(folder: string): void {
|
||||
if (!isValidGroupFolder(folder)) {
|
||||
throw new Error(`Invalid group folder "${folder}"`);
|
||||
}
|
||||
}
|
||||
|
||||
function ensureWithinBase(baseDir: string, resolvedPath: string): void {
|
||||
const rel = path.relative(baseDir, resolvedPath);
|
||||
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
||||
throw new Error(`Path escapes base directory: ${resolvedPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveGroupFolderPath(folder: string): string {
|
||||
assertValidGroupFolder(folder);
|
||||
const groupPath = path.resolve(GROUPS_DIR, folder);
|
||||
ensureWithinBase(GROUPS_DIR, groupPath);
|
||||
return groupPath;
|
||||
}
|
||||
|
||||
export function resolveGroupIpcPath(folder: string): string {
|
||||
assertValidGroupFolder(folder);
|
||||
const ipcBaseDir = path.resolve(DATA_DIR, 'ipc');
|
||||
const ipcPath = path.resolve(ipcBaseDir, folder);
|
||||
ensureWithinBase(ipcBaseDir, ipcPath);
|
||||
return ipcPath;
|
||||
}
|
||||
Reference in New Issue
Block a user