asdf
Squash the current repository state back into one baseline commit while preserving the README reframing and repository contents. Constraint: User explicitly requested a single squashed commit with subject "asdf" Confidence: high Scope-risk: broad Reversibility: clean Directive: This commit intentionally rewrites published history; coordinate before future force-pushes Tested: git status clean; local history rewritten to one commit; force-pushed main to origin and instructkr Not-tested: Fresh clone verification after push
This commit is contained in:
commit
d2542c9a62
70
src/utils/pdfUtils.ts
Normal file
70
src/utils/pdfUtils.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { getMainLoopModel } from './model/model.js'
|
||||
|
||||
// Document extensions that are handled specially
|
||||
export const DOCUMENT_EXTENSIONS = new Set(['pdf'])
|
||||
|
||||
/**
|
||||
* Parse a page range string into firstPage/lastPage numbers.
|
||||
* Supported formats:
|
||||
* - "5" → { firstPage: 5, lastPage: 5 }
|
||||
* - "1-10" → { firstPage: 1, lastPage: 10 }
|
||||
* - "3-" → { firstPage: 3, lastPage: Infinity }
|
||||
*
|
||||
* Returns null on invalid input (non-numeric, zero, inverted range).
|
||||
* Pages are 1-indexed.
|
||||
*/
|
||||
export function parsePDFPageRange(
|
||||
pages: string,
|
||||
): { firstPage: number; lastPage: number } | null {
|
||||
const trimmed = pages.trim()
|
||||
if (!trimmed) {
|
||||
return null
|
||||
}
|
||||
|
||||
// "N-" open-ended range
|
||||
if (trimmed.endsWith('-')) {
|
||||
const first = parseInt(trimmed.slice(0, -1), 10)
|
||||
if (isNaN(first) || first < 1) {
|
||||
return null
|
||||
}
|
||||
return { firstPage: first, lastPage: Infinity }
|
||||
}
|
||||
|
||||
const dashIndex = trimmed.indexOf('-')
|
||||
if (dashIndex === -1) {
|
||||
// Single page: "5"
|
||||
const page = parseInt(trimmed, 10)
|
||||
if (isNaN(page) || page < 1) {
|
||||
return null
|
||||
}
|
||||
return { firstPage: page, lastPage: page }
|
||||
}
|
||||
|
||||
// Range: "1-10"
|
||||
const first = parseInt(trimmed.slice(0, dashIndex), 10)
|
||||
const last = parseInt(trimmed.slice(dashIndex + 1), 10)
|
||||
if (isNaN(first) || isNaN(last) || first < 1 || last < 1 || last < first) {
|
||||
return null
|
||||
}
|
||||
return { firstPage: first, lastPage: last }
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if PDF reading is supported with the current model.
|
||||
* PDF document blocks work on all providers (1P, Vertex, Bedrock, Foundry).
|
||||
* Haiku 3 is the only remaining model that predates PDF support; users on
|
||||
* it fall back to the page-extraction path (poppler-utils). Substring match
|
||||
* covers all provider ID formats (Bedrock prefixes, Vertex @-dates).
|
||||
*/
|
||||
export function isPDFSupported(): boolean {
|
||||
return !getMainLoopModel().toLowerCase().includes('claude-3-haiku')
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file extension is a PDF document.
|
||||
* @param ext File extension (with or without leading dot)
|
||||
*/
|
||||
export function isPDFExtension(ext: string): boolean {
|
||||
const normalized = ext.startsWith('.') ? ext.slice(1) : ext
|
||||
return DOCUMENT_EXTENSIONS.has(normalized.toLowerCase())
|
||||
}
|
||||
Reference in New Issue
Block a user