| 95 | }; |
| 96 | |
| 97 | export function createLocalArtifactAdapter( |
| 98 | options: LocalArtifactAdapterOptions = {}, |
| 99 | ): ArtifactAdapter { |
| 100 | const cwd = options.cwd ?? process.cwd(); |
| 101 | const tempDir = options.tempDir ?? os.tmpdir(); |
| 102 | const rootDir = options.rootDir ? resolveLocalPath(options.rootDir, cwd) : undefined; |
| 103 | |
| 104 | return { |
| 105 | resolveInput: async (ref) => { |
| 106 | if (ref.kind === 'uploadedArtifact') { |
| 107 | throw new AppError( |
| 108 | 'UNSUPPORTED_OPERATION', |
| 109 | 'Uploaded artifact inputs require a custom artifact adapter', |
| 110 | ); |
| 111 | } |
| 112 | return { path: resolveLocalPath(ref.path, cwd, rootDir) }; |
| 113 | }, |
| 114 | reserveOutput: async (ref, outputOptions) => { |
| 115 | let tempRoot: string | undefined; |
| 116 | const visibility = outputOptions.visibility ?? 'client-visible'; |
| 117 | const outputPath = |
| 118 | ref?.kind === 'path' |
| 119 | ? resolveLocalPath(ref.path, cwd, rootDir) |
| 120 | : path.join( |
| 121 | (tempRoot = await fs.mkdtemp( |
| 122 | path.join(tempDir, `agent-device-${outputOptions.field}-`), |
| 123 | )), |
| 124 | `${outputOptions.field}${outputOptions.ext}`, |
| 125 | ); |
| 126 | await fs.mkdir(path.dirname(outputPath), { recursive: true }); |
| 127 | return { |
| 128 | path: outputPath, |
| 129 | visibility, |
| 130 | ...(tempRoot |
| 131 | ? { |
| 132 | cleanup: async () => { |
| 133 | await fs.rm(tempRoot, { recursive: true, force: true }); |
| 134 | }, |
| 135 | } |
| 136 | : {}), |
| 137 | publish: async () => |
| 138 | ref?.kind === 'downloadableArtifact' |
| 139 | ? { |
| 140 | kind: 'localPath', |
| 141 | field: outputOptions.field, |
| 142 | path: outputPath, |
| 143 | fileName: ref.fileName ?? path.basename(ref.clientPath ?? outputPath), |
| 144 | } |
| 145 | : undefined, |
| 146 | }; |
| 147 | }, |
| 148 | createTempFile: async (tempOptions) => { |
| 149 | const root = await fs.mkdtemp(path.join(tempDir, `${tempOptions.prefix}-`)); |
| 150 | return { |
| 151 | path: path.join(root, `file${tempOptions.ext}`), |
| 152 | visibility: 'internal', |
| 153 | cleanup: async () => { |
| 154 | await fs.rm(root, { recursive: true, force: true }); |