Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/commands/documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function extractDocumentIdFromUrl(url: string): string | null {
}

return docSlug.substring(lastHyphenIndex + 1) || null;
} catch {
} catch (_error) {
// URL constructor throws on malformed URLs - treat as non-Linear URL
// This is intentional: attachments may contain arbitrary URLs that aren't
// valid, and we simply skip them rather than failing the entire operation
Expand Down
6 changes: 4 additions & 2 deletions src/utils/embed-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ export function isLinearUploadUrl(url: string): boolean {
try {
const urlObj = new URL(url);
return urlObj.hostname === "uploads.linear.app";
} catch {
} catch (_error) {
// Invalid URLs are expected when parsing arbitrary markdown content.
return false;
}
}
Expand All @@ -127,7 +128,8 @@ export function extractFilenameFromUrl(url: string): string {
const pathname = urlObj.pathname;
const parts = pathname.split("/");
return parts[parts.length - 1] || "download";
} catch {
} catch (_error) {
// Fall back to a generic filename when the URL cannot be parsed.
return "download";
}
}
29 changes: 25 additions & 4 deletions src/utils/file-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ function getMimeType(filePath: string): string {
return MIME_TYPES[ext] || "application/octet-stream";
}

function isMissingFileError(error: unknown): boolean {
return (
error instanceof Error &&
(("code" in error && error.code === "ENOENT") || error.message === "ENOENT")
);
}

export interface DownloadOptions {
/** Custom output file path (defaults to filename from URL) */
output?: string;
Expand Down Expand Up @@ -172,8 +179,15 @@ export class FileService {
error:
`File already exists: ${outputPath}. Use --overwrite to replace.`,
};
} catch {
// File doesn't exist, we can proceed
} catch (error) {
if (isMissingFileError(error)) {
// Missing output path is expected here; we'll create it below.
} else {
return {
success: false,
error: error instanceof Error ? error.message : String(error),
};
}
}
}

Expand Down Expand Up @@ -255,10 +269,17 @@ export class FileService {
// Check if file exists
try {
await access(filePath);
} catch {
} catch (error) {
if (isMissingFileError(error)) {
return {
success: false,
error: `File not found: ${filePath}`,
};
}

return {
success: false,
error: `File not found: ${filePath}`,
error: error instanceof Error ? error.message : String(error),
};
}

Expand Down
5 changes: 3 additions & 2 deletions src/utils/identifier-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ export function parseIssueIdentifier(identifier: string): ParsedIssueIdentifier
export function tryParseIssueIdentifier(identifier: string): ParsedIssueIdentifier | null {
try {
return parseIssueIdentifier(identifier);
} catch {
} catch (_error) {
// Invalid TEAM-123 values are expected in permissive parsing paths.
return null;
}
}
}
4 changes: 2 additions & 2 deletions src/utils/linear-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,8 @@ export class LinearService {
teamKeyOrNameOrId,
);
return team.id;
} catch {
// If not found by key, try by name
} catch (_error) {
// Not every caller passes a team key; fall back to an exact name lookup.
const team = await executeLinearQuery(
() =>
this.client.teams({
Expand Down
Loading