(sourcePath: string | null)
| 299 | } |
| 300 | |
| 301 | export function isEditableCurrentSourcePath(sourcePath: string | null): boolean { |
| 302 | if (!sourcePath || !path.isAbsolute(sourcePath) || !isMarkdownPath(sourcePath)) { |
| 303 | return false; |
| 304 | } |
| 305 | const resolvedSourcePath = path.resolve(sourcePath); |
| 306 | const blockedRoots = [ |
| 307 | path.resolve(runtimeContextSessionsDir()), |
| 308 | path.resolve(legacyCodexContextSessionsDir()), |
| 309 | ]; |
| 310 | if (blockedRoots.some((root) => isPathInside(root, resolvedSourcePath))) { |
| 311 | return false; |
| 312 | } |
| 313 | const allowedRoots = Array.from(new Set([ |
| 314 | path.resolve(canonicalLibraryDir()), |
| 315 | path.resolve(path.join(fieldTheoryDir(), 'librarian', 'artifacts')), |
| 316 | path.resolve(path.join(fieldTheoryRoot(), 'librarian', 'artifacts')), |
| 317 | ])); |
| 318 | if (!allowedRoots.some((root) => isPathInside(root, resolvedSourcePath))) { |
| 319 | return false; |
| 320 | } |
| 321 | try { |
| 322 | return fs.statSync(resolvedSourcePath).isFile(); |
| 323 | } catch { |
| 324 | return false; |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | function sourceDocumentVersion(sourcePath: string | null): DocumentVersion | null { |
| 329 | if (!isEditableCurrentSourcePath(sourcePath)) return null; |
no test coverage detected