diff --git a/package.json b/package.json index ae984082..9e811af2 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "package:linux": "node scripts/set-version.mjs npm run build && node scripts/set-version.mjs electron-builder --linux", "start": "electron .", "clean": "rm -rf dist release node_modules/.vite", - "prepare": "husky || true", + "prepare": "echo 'No prepare script'", "postinstall": "electron-rebuild -f -w node-pty,better-sqlite3", "lint": "tsc -p tsconfig.lint.json && tsc -p tsconfig.main.json --noEmit && tsc -p tsconfig.cli.json --noEmit", "lint:eslint": "eslint src/", @@ -289,9 +289,7 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.0.1", "globals": "^16.5.0", - "husky": "^9.1.7", "jsdom": "^27.2.0", - "lint-staged": "^16.2.7", "lucide-react": "^0.303.0", "playwright": "^1.57.0", "postcss": "^8.4.33", @@ -307,14 +305,5 @@ }, "engines": { "node": ">=22.0.0" - }, - "lint-staged": { - "src/**/*.{ts,tsx}": [ - "prettier --write", - "eslint --fix" - ], - "src/**/*.{json,css,md}": [ - "prettier --write" - ] } } diff --git a/src/main/parsers/factory-droid-output-parser.ts b/src/main/parsers/factory-droid-output-parser.ts index b9c49f5f..659bd131 100644 --- a/src/main/parsers/factory-droid-output-parser.ts +++ b/src/main/parsers/factory-droid-output-parser.ts @@ -57,6 +57,21 @@ interface FactoryStreamMessage { }; } +/** + * Type guard to validate parsed JSON matches FactoryStreamMessage structure + */ +function isFactoryStreamMessage(data: unknown): data is FactoryStreamMessage { + if (typeof data !== 'object' || data === null) { + return false; + } + const obj = data as Record; + // Must have a valid type field + return ( + typeof obj.type === 'string' && + ['system', 'message', 'completion', 'error'].includes(obj.type) + ); +} + /** * Factory Droid Output Parser Implementation * @@ -74,7 +89,20 @@ export class FactoryDroidOutputParser implements AgentOutputParser { } try { - const data: FactoryStreamMessage = JSON.parse(line); + const parsed: unknown = JSON.parse(line); + + // Validate the parsed JSON matches expected structure + if (!isFactoryStreamMessage(parsed)) { + // Valid JSON but not a Factory message - return as raw text + return { + type: 'text', + text: line, + isPartial: true, + raw: parsed, + }; + } + + const data = parsed; switch (data.type) { case 'system': diff --git a/src/main/storage/factory-droid-session-storage.ts b/src/main/storage/factory-droid-session-storage.ts index 97e15f34..3ab198d1 100644 --- a/src/main/storage/factory-droid-session-storage.ts +++ b/src/main/storage/factory-droid-session-storage.ts @@ -106,8 +106,9 @@ interface FactorySettings { */ function encodeProjectPath(projectPath: string): string { // Normalize and encode: /Users/octavia/proj -> -Users-octavia-proj + // Handle both forward slashes (Unix) and backslashes (Windows) const normalized = path.resolve(projectPath); - return normalized.replace(/\//g, '-'); + return normalized.replace(/[\\/]/g, '-'); } /** @@ -117,7 +118,8 @@ async function readJsonFile(filePath: string): Promise { try { const content = await fs.readFile(filePath, 'utf-8'); return JSON.parse(content) as T; - } catch { + } catch (error) { + logger.debug(`Failed to read JSON file: ${filePath}`, LOG_CONTEXT, { error }); return null; } } @@ -171,13 +173,14 @@ export class FactoryDroidSessionStorage implements AgentSessionStorage { if (parsed.type === 'message' && parsed.message) { messages.push(parsed as FactoryMessage); } - } catch { - // Skip unparseable lines + } catch (error) { + logger.debug('Skipping unparseable JSONL line', LOG_CONTEXT, { error }); } } return messages; - } catch { + } catch (error) { + logger.debug(`Failed to load session messages: ${sessionPath}`, LOG_CONTEXT, { error }); return []; } } @@ -529,7 +532,8 @@ export class FactoryDroidSessionStorage implements AgentSessionStorage { } else { newLines.push(line); } - } catch { + } catch (error) { + logger.debug('Skipping unparseable line during deletion', LOG_CONTEXT, { error }); newLines.push(line); } }