mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 00:19:42 +02:00
refactor: pass 2 — extract shared helpers and simplify patterns
app.js: - Add _clearTimer() helper replacing 11 inline clearTimeout patterns - Add _isStaleSelect() helper for generation check + cleanup - Replace 11 keyboard shortcut if-blocks with data-driven lookup table - Extract _cleanupPreviousSession() from selectSession() (~75 lines) - Extract _resetAllAppState() from handleInit() (~75 lines) tmux-manager: - Extract buildEnvExports() eliminating duplication in createSession/respawnPane - Extract buildPathExport() for CLI path resolution - Extract _configureOpenCode() for OpenCode setup routes: - Add readJsonConfig() to route-helpers, replacing 5 inline JSON-read patterns - Add validateSessionFilePath() to route-helpers, replacing 2 identical path traversal validation blocks in file-routes session-auto-ops: - Convert executeWhenIdle() from 8 positional params to options object - Extract validateThreshold() for shared compact/clear validation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
*/
|
||||
|
||||
import { join, resolve, relative, isAbsolute } from 'node:path';
|
||||
import { realpathSync } from 'node:fs';
|
||||
import fs from 'node:fs/promises';
|
||||
import { homedir } from 'node:os';
|
||||
import type { z } from 'zod';
|
||||
import { Session } from '../session.js';
|
||||
@@ -33,6 +35,45 @@ export function validatePathWithinBase(name: string, baseDir: string): string |
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and parses a JSON config file, returning a default value on ENOENT.
|
||||
* Logs an error for any I/O failure other than a missing file.
|
||||
*/
|
||||
export async function readJsonConfig<T>(filePath: string, logLabel: string, defaultValue: T): Promise<T> {
|
||||
try {
|
||||
const content = await fs.readFile(filePath, 'utf-8');
|
||||
return JSON.parse(content) as T;
|
||||
} catch (err) {
|
||||
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
console.error(`Failed to read ${logLabel}:`, err);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a file path (possibly containing symlinks) resolves to a location
|
||||
* within the given session working directory. Returns the resolved and relative paths,
|
||||
* or null if the path escapes the directory or doesn't exist.
|
||||
*/
|
||||
export function validateSessionFilePath(
|
||||
sessionWorkingDir: string,
|
||||
filePath: string
|
||||
): { resolvedPath: string; relativePath: string } | null {
|
||||
const fullPath = resolve(sessionWorkingDir, filePath);
|
||||
let resolvedPath: string;
|
||||
try {
|
||||
resolvedPath = realpathSync(fullPath);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
const relativePath = relative(sessionWorkingDir, resolvedPath);
|
||||
if (relativePath.startsWith('..') || isAbsolute(relativePath)) {
|
||||
return null;
|
||||
}
|
||||
return { resolvedPath, relativePath };
|
||||
}
|
||||
|
||||
// Maximum hook data size (prevents oversized SSE broadcasts)
|
||||
const MAX_HOOK_DATA_SIZE = 8 * 1024;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user