* Execute BYOC mode persistence: scan local filesystem for modified files, * then upload to Files API.
( turnStartTime: TurnStartTime, config: FilesApiConfig, outputsDir: string, signal?: AbortSignal, )
| 156 | * then upload to Files API. |
| 157 | */ |
| 158 | async function executeBYOCPersistence( |
| 159 | turnStartTime: TurnStartTime, |
| 160 | config: FilesApiConfig, |
| 161 | outputsDir: string, |
| 162 | signal?: AbortSignal, |
| 163 | ): Promise<FilesPersistedEventData> { |
| 164 | // Find modified files via local filesystem scan |
| 165 | // Uses same directory structure as downloads: {cwd}/{sessionId}/outputs |
| 166 | const modifiedFiles = await findModifiedFiles(turnStartTime, outputsDir) |
| 167 | |
| 168 | if (modifiedFiles.length === 0) { |
| 169 | logDebug('No modified files to persist') |
| 170 | return { files: [], failed: [] } |
| 171 | } |
| 172 | |
| 173 | logDebug(`Found ${modifiedFiles.length} modified files`) |
| 174 | |
| 175 | if (signal?.aborted) { |
| 176 | return { files: [], failed: [] } |
| 177 | } |
| 178 | |
| 179 | // Enforce file count limit |
| 180 | if (modifiedFiles.length > FILE_COUNT_LIMIT) { |
| 181 | logDebug( |
| 182 | `File count limit exceeded: ${modifiedFiles.length} > ${FILE_COUNT_LIMIT}`, |
| 183 | ) |
| 184 | logEvent('ncode_file_persistence_limit_exceeded', { |
| 185 | file_count: modifiedFiles.length, |
| 186 | limit: FILE_COUNT_LIMIT, |
| 187 | }) |
| 188 | return { |
| 189 | files: [], |
| 190 | failed: [ |
| 191 | { |
| 192 | filename: outputsDir, |
| 193 | error: `Too many files modified (${modifiedFiles.length}). Maximum: ${FILE_COUNT_LIMIT}.`, |
| 194 | }, |
| 195 | ], |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | const filesToProcess = modifiedFiles |
| 200 | .map(filePath => ({ |
| 201 | path: filePath, |
| 202 | relativePath: relative(outputsDir, filePath), |
| 203 | })) |
| 204 | .filter(({ relativePath }) => { |
| 205 | // Security: skip files that resolve outside the outputs directory |
| 206 | if (relativePath.startsWith('..')) { |
| 207 | logDebug(`Skipping file outside outputs directory: ${relativePath}`) |
| 208 | return false |
| 209 | } |
| 210 | return true |
| 211 | }) |
| 212 | |
| 213 | logDebug(`BYOC mode: uploading ${filesToProcess.length} files`) |
| 214 | |
| 215 | // Upload files in parallel |
no test coverage detected