* Common project setup: resolve path, parse/convert file, validate requirements. * Shared by both runDeepnoteProject and dryRunDeepnoteProject. * * Supports multiple file formats: * - .deepnote - Native format (no conversion) * - .ipynb - Jupyter Notebook (auto-converted) * - .py - Percent or
(path: string | undefined, options: RunOptions)
| 259 | * - .qmd - Quarto document (auto-converted) |
| 260 | */ |
| 261 | async function setupProject(path: string | undefined, options: RunOptions): Promise<ProjectSetup> { |
| 262 | const isMachineOutput = options.output !== undefined |
| 263 | |
| 264 | let file: DeepnoteFile |
| 265 | let absolutePath: string |
| 266 | let convertedFile: LoadedRunnableFile |
| 267 | let workingDirectory: string |
| 268 | |
| 269 | if (!path && options.prompt) { |
| 270 | file = createPromptOnlyFile(options.prompt) |
| 271 | absolutePath = join(process.cwd(), 'prompt.deepnote') |
| 272 | workingDirectory = options.cwd ?? process.cwd() |
| 273 | convertedFile = { file, originalPath: absolutePath, format: 'deepnote', wasConverted: true } |
| 274 | if (!isMachineOutput) { |
| 275 | log(getChalk().dim('Running agent block...')) |
| 276 | } |
| 277 | } else { |
| 278 | if (!path) { |
| 279 | throw new Error('A file path is required when --prompt is not provided') |
| 280 | } |
| 281 | convertedFile = await resolveAndConvertToDeepnote(path) |
| 282 | const { originalPath, wasConverted, format } = convertedFile |
| 283 | file = convertedFile.file |
| 284 | absolutePath = originalPath |
| 285 | workingDirectory = options.cwd ?? dirname(absolutePath) |
| 286 | if (!isMachineOutput) { |
| 287 | if (wasConverted) { |
| 288 | log(getChalk().dim(`Converting ${format} file: ${absolutePath}...`)) |
| 289 | } else { |
| 290 | log(getChalk().dim(`Parsing ${absolutePath}...`)) |
| 291 | } |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | // Sibling-init resolution only applies to native .deepnote files (handled inside the shared helper). |
| 296 | const resolved = await resolveAndComposeInitIfNeeded(convertedFile) |
| 297 | file = resolved.file |
| 298 | emitInitResolverWarnings(resolved.warnings, isMachineOutput) |
| 299 | |
| 300 | if (path && options.prompt) { |
| 301 | const lastNotebook = file.project.notebooks[file.project.notebooks.length - 1] |
| 302 | if (lastNotebook) { |
| 303 | lastNotebook.blocks.push(createAgentBlock(options.prompt, lastNotebook.blocks.length)) |
| 304 | } else { |
| 305 | throw new Error('Cannot append prompt: file contains no notebooks') |
| 306 | } |
| 307 | } |
| 308 | |
| 309 | dotenv.config({ path: join(workingDirectory, DEFAULT_ENV_FILE), quiet: true }) |
| 310 | |
| 311 | const pythonEnv = await resolvePythonExecutable(options.python ?? detectDefaultPython()) |
| 312 | |
| 313 | const inputs = parseInputs(options.input) |
| 314 | |
| 315 | // Parse integrations file (if it exists) |
| 316 | const integrationsFilePath = getDefaultIntegrationsFilePath(workingDirectory) |
| 317 | const parsedIntegrations = await parseIntegrationsFile(integrationsFilePath) |
| 318 |
no test coverage detected