type === 'linkedin'; } public function publish(Post $post, ?SocialAccount $socialAccount = null): PublishResult { if (! $post->body) { return PublishResult::rejected("Post {$post->id} has no body, required for a LinkedIn post."); } // Use the passed social account, or fall back to the first linked one $account = $socialAccount ?: $post->socialAccounts->first(); if (! $account || $account->network !== 'linkedin') { return PublishResult::rejected("Post {$post->id} has no linked LinkedIn social account."); } // LinkedIn uses email and password $result = Process::timeout(120)->run([ base_path('sidecars/linkedin-post/run.sh'), "--email={$account->email}", "--password={$account->password}", "--post=" . escapeshellarg($post->body), ]); $data = json_decode(trim($result->output()), true); if (! is_array($data) || ! array_key_exists('success', $data)) { Log::error('linkedin sidecar returned unparseable output', [ 'post_id' => $post->id, 'output' => $result->output(), 'stderr' => $result->errorOutput(), ]); return PublishResult::failed('LinkedIn sidecar returned unparseable output — check logs.'); } if (! $data['success']) { return PublishResult::failed($data['error'] ?? 'unknown LinkedIn sidecar failure'); } return PublishResult::success($data['url']); } }