refactor(convert): extract shared runnable-file loading & snapshot persistence - #408
Conversation
…rsistence Lift the runnable-file loader and execution-snapshot helpers that were duplicated between @deepnote/cli and @deepnote/mcp into @deepnote/convert, and point both consumers at the shared implementations. The two copies had drifted (error wrapping, return shapes, stale-executionCount handling); this unifies them. - convert: new load-runnable-file.ts (loadRunnableFile, isRunnableExtension, RUNNABLE_EXTENSIONS, LoadRunnableFileError) and snapshot/save-execution-snapshot.ts (saveExecutionSnapshot, mergeOutputsIntoFile, getSnapshotPath) - generateSnapshotFilename now takes an object parameter (output byte-identical) - cli format-converter.ts / output-persistence.ts become thin wrappers that keep CLI-only concerns (directory rejection, FileResolutionError, debug logging, IOutput[]-typed public surface) - mcp execution.ts delegates to the shared helpers; local copies removed Behavior is preserved for existing inputs, with two deliberate, documented changes: - mergeOutputsIntoFile now retains a stale executionCount (MCP semantics), pinned by a new test - filesystem read errors keep their Node code (ENOENT/EISDIR) so MCP's error envelope is unchanged; only unsupported-extension/parse failures throw the code-less LoadRunnableFileError Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughFormat detection/conversion and snapshot persistence are extracted from CLI and MCP into Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 6✅ Passed checks (6 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #408 +/- ##
==========================================
+ Coverage 83.94% 84.35% +0.41%
==========================================
Files 151 153 +2
Lines 8047 7996 -51
Branches 2236 2225 -11
==========================================
- Hits 6755 6745 -10
+ Misses 1291 1250 -41
Partials 1 1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/convert/src/load-runnable-file.ts`:
- Around line 73-80: Replace the concatenated template string used in the
LoadRunnableFileError constructor with the dedent function from ts-dedent for
better readability and consistency with project guidelines. Import dedent from
ts-dedent if not already present in the file, then wrap the multiline error
message string with dedent to automatically handle proper indentation and
formatting. Apply this same refactoring to the other similar error message
construction at line 201.
In `@packages/convert/src/snapshot/save-execution-snapshot.ts`:
- Around line 108-110: The timestamp generation in the saveExecutionSnapshot
function is dropping sub-second precision by slicing the ISO string at position
19, which causes file name collisions for executions within the same second.
Modify the slice operation on the timestamp variable to preserve millisecond
precision from the ISO timestamp string after replacing the colon and period
characters, so that multiple snapshots generated in the same second will have
unique filenames.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: d9945608-72d0-4c09-a87a-dcdaf5cfc4ce
📒 Files selected for processing (12)
packages/cli/src/utils/format-converter.tspackages/cli/src/utils/output-persistence.tspackages/convert/src/index.tspackages/convert/src/load-runnable-file.tspackages/convert/src/snapshot/index.tspackages/convert/src/snapshot/save-execution-snapshot.test.tspackages/convert/src/snapshot/save-execution-snapshot.tspackages/convert/src/snapshot/snapshot-integration.test.tspackages/convert/src/snapshot/split.test.tspackages/convert/src/snapshot/split.tspackages/convert/src/write-deepnote-file.tspackages/mcp/src/tools/execution.ts
Remove the backward-compat re-exports that were added when runnable-file loading and snapshot persistence moved into @deepnote/convert, and import the moved symbols directly from the package instead. - output-persistence.ts: drop the getSnapshotPath / mergeOutputsIntoFile / ExecutionTiming re-exports (they had no consumers) - format-converter.ts: drop the isRunnableExtension / RUNNABLE_EXTENSIONS / RunnableExtension re-exports - format-converter.test.ts: the only consumer of a removed re-export — now imports isRunnableExtension / RUNNABLE_EXTENSIONS from @deepnote/convert Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to dropping the compat re-export shims: - remove the ConvertedFile type alias (a backward-compat rename of LoadedRunnableFile); resolveAndConvertToDeepnote now returns LoadedRunnableFile directly and run.ts imports the type from @deepnote/convert - restore the original BlockExecutionOutput doc comment in output-persistence.ts Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Integrate PR #408 (shared runnable-file loading & snapshot persistence extracted into @deepnote/convert), which was split out of this branch and merged to main. Resolution principle: adopt main's clean extraction as the base, then re-apply this branch's single-notebook feature work on top. Conflict resolutions (12 files): - convert/load-runnable-file.ts: took main's version (preserves fs ENOENT/EISDIR codes on .deepnote reads; this branch had wrapped them into a code-less error). - convert/snapshot/save-execution-snapshot.ts: kept this branch's feature version (notebookId-scoped filenames, init-notebook composed runs, init result paths). Kept the branch's mergeOutputsIntoFile strip semantics (drops stale per-block executionCount + execution timing so a re-run never leaks a prior run's metadata) and rewrote main's pinning test to assert the strip. - convert/snapshot/split.ts + write-deepnote-file.ts: object-param generateSnapshotFilename (from #408) plus this branch's notebookId + sanitizeFilenameComponent additions. - convert barrels (index.ts, snapshot/index.ts): union of #408 exports and the feature exports (resolve-init, snapshot-notebook-id, SaveExecutionSnapshotOptions). - convert test files: object-form generateSnapshotFilename calls. - cli/format-converter.ts: took main's clean thin wrapper (returns LoadedRunnableFile; dropped re-export shims no consumer needs). - cli/output-persistence.ts: main's thin wrapper + this branch's init options and init result paths; dropped the unused mergeOutputsIntoFile/getSnapshotPath shims. - cli/run.ts + mcp/execution.ts: union imports; kept the init composition (resolveAndComposeInit / resolveRunnableWithInit) while preserving main's fs error-code handling contract. Ran pnpm install (main added a `yaml` dep to @deepnote/database-integrations). Verified green: pnpm typecheck, biome:check, build, test (2330 passed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Account for PRs that landed on main after the initial bump: - @deepnote/convert 3.2.3 -> 4.0.0 (patch -> MAJOR): #364 and #408 rename/remove many public exports (convertIpynbFilesToDeepnoteFile -> convertIpynbFileToDeepnoteFile, etc.) and switch the .deepnote format to single-notebook-per-file — breaking changes for a published 3.x package. - @deepnote/mcp 0.3.3 -> 0.4.0 (patch -> minor): #364/#408 change tool behavior (single-notebook conversion output, notebook-scoped snapshots), so it is no longer a dependency-bump-only release. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore: bump package versions Release the changes that have accumulated on main since the last tag for each package: - @deepnote/blocks 4.5.1 -> 4.6.0 - @deepnote/cli 0.6.1 -> 0.7.0 - @deepnote/convert 3.2.2 -> 3.2.3 - @deepnote/database-integrations 1.4.3 -> 1.5.0 - @deepnote/mcp 0.3.2 -> 0.3.3 - @deepnote/reactivity 1.2.0 -> 1.2.1 - @deepnote/runtime-core 0.3.0 -> 0.4.0 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: correct convert (major) and mcp (minor) bumps Account for PRs that landed on main after the initial bump: - @deepnote/convert 3.2.3 -> 4.0.0 (patch -> MAJOR): #364 and #408 rename/remove many public exports (convertIpynbFilesToDeepnoteFile -> convertIpynbFileToDeepnoteFile, etc.) and switch the .deepnote format to single-notebook-per-file — breaking changes for a published 3.x package. - @deepnote/mcp 0.3.3 -> 0.4.0 (patch -> minor): #364/#408 change tool behavior (single-notebook conversion output, notebook-scoped snapshots), so it is no longer a dependency-bump-only release. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Lifts the runnable-file loader and execution-snapshot persistence helpers that were duplicated between
@deepnote/cliand@deepnote/mcpinto the shared@deepnote/convertpackage, and points both consumers at the shared implementations. The two copies had drifted (error wrapping, return shapes, stale-executionCounthandling); this unifies them.Changes
@deepnote/convert(new shared code)load-runnable-file.ts—loadRunnableFile,isRunnableExtension,RUNNABLE_EXTENSIONS,LoadRunnableFileErrorsnapshot/save-execution-snapshot.ts—saveExecutionSnapshot,mergeOutputsIntoFile,getSnapshotPathgenerateSnapshotFilenamenow takes an object parameter (output byte-identical)@deepnote/cli—format-converter.tsandoutput-persistence.tsbecome thin wrappers retaining CLI-only concerns (directory rejection,FileResolutionError,debug()logging,IOutput[]-typed public surface)@deepnote/mcp—execution.tsdelegates to the shared helpers; the local copies are removedBehavior preservation
Behavior is preserved for existing inputs, with two deliberate, documented changes:
mergeOutputsIntoFilenow retains a staleexecutionCount(adopts the MCP merge semantics; pinned by a new test).code(ENOENT/EISDIR) so MCP's error envelope is unchanged; only unsupported-extension/parse failures throw the code-lessLoadRunnableFileError.Out of scope (builds on top of this): single-notebook / init-notebook resolution,
resolveSnapshotNotebookId,splitByNotebooks/ thedeepnote splitcommand, filename sanitization.Verification
pnpm build,pnpm typecheck,pnpm biome:check, andpnpm test(132 files / 2251 tests) all green.dist: a missing or directory.deepnotepreservesENOENT/EISDIRthroughloadRunnableFile, while unsupported-extension and parse failures stay code-less — so MCP'sdeepnote_runerror envelope (incl.code) matchesmain.🤖 Generated with Claude Code
Summary by CodeRabbit