tithon 0.2.2__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tithon-0.2.3/.git-blame-ignore-revs +9 -0
- tithon-0.2.3/.release-please-manifest.json +4 -0
- tithon-0.2.3/.vscode/extensions.json +3 -0
- tithon-0.2.3/.vscode/settings.json +28 -0
- {tithon-0.2.2 → tithon-0.2.3}/CHANGELOG.md +19 -0
- {tithon-0.2.2 → tithon-0.2.3}/PKG-INFO +29 -2
- {tithon-0.2.2 → tithon-0.2.3}/README.md +28 -1
- {tithon-0.2.2 → tithon-0.2.3}/docs/SPEC.md +46 -5
- {tithon-0.2.2 → tithon-0.2.3}/extension/CHANGELOG.md +16 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/README.md +19 -2
- tithon-0.2.3/extension/biome.json +39 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/runTest.ts +8 -4
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/seed.ts +3 -3
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/addcell.test.ts +5 -2
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/autoopen.test.ts +41 -15
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/autostart.test.ts +31 -12
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_addmd.test.ts +11 -5
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_editsave.test.ts +13 -5
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_emptycell.test.ts +47 -13
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_imageorder.test.ts +31 -9
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_input_hang.test.ts +52 -15
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_insert_reconnect.test.ts +52 -19
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_insertheader.test.ts +6 -4
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_kerneldeath.test.ts +14 -5
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_mdsave.test.ts +5 -3
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_rerun.test.ts +50 -18
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_rerun_reconnect.test.ts +56 -18
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_runall_error.test.ts +33 -10
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_runall_md.test.ts +15 -5
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/bug_staleedit.test.ts +43 -14
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/celltoggle.test.ts +54 -21
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/clearspinner.test.ts +34 -15
- tithon-0.2.3/extension/integration/suite/closedsession.test.ts +161 -0
- tithon-0.2.3/extension/integration/suite/confirmdestructive.test.ts +175 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/crosscell.test.ts +40 -14
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/demo.test.ts +70 -26
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/disposeflush.test.ts +28 -14
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/dupcode.test.ts +18 -7
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/editedcell.test.ts +6 -7
- tithon-0.2.3/extension/integration/suite/editorpin.test.ts +465 -0
- tithon-0.2.3/extension/integration/suite/index.ts +44 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/interrupt.test.ts +48 -13
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/live.test.ts +19 -10
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/livedisplay.test.ts +16 -9
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/livereconnect.test.ts +57 -18
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/lsp.test.ts +45 -23
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/lspdef.test.ts +26 -13
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/lspinlay.test.ts +63 -24
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/lsproundtrip.test.ts +37 -19
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/multicell.test.ts +29 -13
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/opentextshot.test.ts +6 -10
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/orphanrestore.test.ts +18 -7
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/reconnect.test.ts +48 -19
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/reconnectprogress.test.ts +41 -17
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/reconnectstates.test.ts +54 -19
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/reopen.test.ts +24 -9
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/reopenafterroundtrip.test.ts +38 -15
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/restartdaemon.test.ts +45 -18
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/restartkernel.test.ts +27 -10
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/restore.test.ts +2 -4
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/richoutputs.test.ts +73 -31
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/runcell.test.ts +14 -4
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/screenshot.test.ts +23 -11
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/trainloop.test.ts +41 -18
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/trainsync.test.ts +89 -35
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/twofiles.test.ts +22 -8
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/widget.test.ts +31 -11
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/widgetdisposeflush.test.ts +24 -8
- {tithon-0.2.2 → tithon-0.2.3}/extension/integration/suite/widgetlive.test.ts +33 -10
- {tithon-0.2.2 → tithon-0.2.3}/extension/package-lock.json +303 -7
- {tithon-0.2.2 → tithon-0.2.3}/extension/package.json +71 -8
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/cellAttach.ts +8 -7
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/codeLens.ts +1 -1
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/daemonClient.ts +30 -15
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/daemonProcess.ts +39 -17
- tithon-0.2.3/extension/src/extension.ts +681 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/liveSync.ts +10 -12
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/notebookSerializer.ts +6 -12
- tithon-0.2.3/extension/src/notify.ts +69 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/outputFold.ts +19 -3
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/richOutput.ts +25 -15
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/serializer.ts +7 -7
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/sessionClient.ts +93 -37
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/sessionController.ts +338 -153
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/tracebackFormatter.ts +3 -2
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/widgetRender.ts +4 -6
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/widgetRendererEntry.ts +16 -17
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/artifactCache.test.ts +16 -4
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/cellAttach.test.ts +23 -5
- tithon-0.2.3/extension/test/closedSession.test.ts +98 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/fakeDaemon.ts +19 -7
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/kernelGeneration.test.ts +38 -15
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/liveDaemon.ts +3 -3
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/liveSync.test.ts +46 -15
- tithon-0.2.3/extension/test/notify.test.ts +86 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/outputFold.test.ts +79 -23
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/reconnectClient.test.ts +7 -4
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/restore.test.ts +5 -4
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/richDaemon.test.ts +12 -6
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/richOutput.test.ts +50 -12
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/serializer.test.ts +15 -24
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/setup.ts +1 -5
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/tracebackFormatter.test.ts +8 -4
- tithon-0.2.3/extension/test/vscodeMock.ts +75 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/widget.test.ts +6 -5
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/widgetBuffers.test.ts +24 -9
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/widgetEvents.test.ts +26 -11
- tithon-0.2.3/extension/vitest.config.ts +24 -0
- {tithon-0.2.2 → tithon-0.2.3}/pyproject.toml +27 -2
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_check_input_bridge.py +3 -1
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_check_interrupt_priority.py +24 -14
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_check_kernel_death.py +17 -6
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_check_multi.py +73 -37
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_check_v1.py +4 -1
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_check_v2.py +1 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_check_v3.py +2 -3
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_check_v5.py +3 -6
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_clear_client.py +8 -4
- tithon-0.2.3/scripts/_clone_client.py +75 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_lastseq.py +1 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_multi_client.py +17 -7
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_stalled_client.py +1 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/_workdir_client.py +18 -8
- {tithon-0.2.2 → tithon-0.2.3}/scripts/run_verify.sh +10 -10
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v39.sh +2 -2
- tithon-0.2.3/scripts/v61.sh +98 -0
- tithon-0.2.3/scripts/v62.sh +78 -0
- tithon-0.2.3/scripts/v63.sh +41 -0
- tithon-0.2.3/scripts/v64.sh +95 -0
- tithon-0.2.3/scripts/v65.sh +61 -0
- {tithon-0.2.2 → tithon-0.2.3}/src/tithon/__main__.py +1 -0
- {tithon-0.2.2 → tithon-0.2.3}/src/tithon/artifacts.py +1 -0
- {tithon-0.2.2 → tithon-0.2.3}/src/tithon/cli.py +15 -6
- {tithon-0.2.2 → tithon-0.2.3}/src/tithon/daemon.py +381 -131
- {tithon-0.2.2 → tithon-0.2.3}/src/tithon/folding.py +36 -8
- {tithon-0.2.2 → tithon-0.2.3}/src/tithon/journal.py +164 -39
- {tithon-0.2.2 → tithon-0.2.3}/src/tithon/kernel.py +1 -0
- tithon-0.2.3/src/tithon/sidecar.py +258 -0
- {tithon-0.2.2 → tithon-0.2.3}/src/tithon/widgets.py +8 -4
- {tithon-0.2.2 → tithon-0.2.3}/test/test_artifacts.py +17 -6
- {tithon-0.2.2 → tithon-0.2.3}/test/test_backpressure.py +1 -2
- {tithon-0.2.2 → tithon-0.2.3}/test/test_barrier.py +11 -5
- {tithon-0.2.2 → tithon-0.2.3}/test/test_clear.py +4 -3
- tithon-0.2.3/test/test_closed_by_user.py +87 -0
- {tithon-0.2.2 → tithon-0.2.3}/test/test_comm_ordering.py +16 -4
- {tithon-0.2.2 → tithon-0.2.3}/test/test_display_registry.py +7 -10
- {tithon-0.2.2 → tithon-0.2.3}/test/test_folding.py +165 -79
- {tithon-0.2.2 → tithon-0.2.3}/test/test_gc.py +1 -0
- {tithon-0.2.2 → tithon-0.2.3}/test/test_inflight_recovery.py +20 -19
- {tithon-0.2.2 → tithon-0.2.3}/test/test_journal_origin.py +21 -5
- {tithon-0.2.2 → tithon-0.2.3}/test/test_kernel_group_kill.py +1 -0
- {tithon-0.2.2 → tithon-0.2.3}/test/test_kill_restart_race.py +1 -0
- {tithon-0.2.2 → tithon-0.2.3}/test/test_liveness.py +7 -7
- {tithon-0.2.2 → tithon-0.2.3}/test/test_lost_state.py +10 -5
- {tithon-0.2.2 → tithon-0.2.3}/test/test_orphan.py +5 -2
- {tithon-0.2.2 → tithon-0.2.3}/test/test_payload.py +1 -0
- {tithon-0.2.2 → tithon-0.2.3}/test/test_rebuild_mirror_streaming.py +29 -12
- {tithon-0.2.2 → tithon-0.2.3}/test/test_restart_drain.py +4 -4
- {tithon-0.2.2 → tithon-0.2.3}/test/test_runall_batch.py +5 -9
- {tithon-0.2.2 → tithon-0.2.3}/test/test_session_layout.py +5 -4
- tithon-0.2.3/test/test_sidecar.py +547 -0
- {tithon-0.2.2 → tithon-0.2.3}/test/test_widget_buffer_delta.py +36 -11
- {tithon-0.2.2 → tithon-0.2.3}/test/test_widgets.py +46 -20
- {tithon-0.2.2 → tithon-0.2.3}/uv.lock +28 -1
- tithon-0.2.2/.release-please-manifest.json +0 -4
- tithon-0.2.2/extension/integration/suite/index.ts +0 -25
- tithon-0.2.2/extension/src/extension.ts +0 -499
- tithon-0.2.2/extension/vitest.config.ts +0 -14
- {tithon-0.2.2 → tithon-0.2.3}/.claude/settings.local.json +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/.gitattributes +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/.github/scripts/format-release-pr-body.js +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/.github/scripts/format-release-pr-body.test.js +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/.github/workflows/release-please.yml +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/.gitignore +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/LICENSE +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/docs/demo.gif +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/docs/demo.mp4 +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/docs/how-it-works.png +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/docs/index.html +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/docs/known_issue.md +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/docs/vscode-jupyter-comparison.md +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/.vscodeignore +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/LICENSE +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/esbuild.mjs +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/icon.png +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/artifactCache.ts +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/css.d.ts +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/src/widgetTheme.css +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/test/fixtures/tqdm_widget_state.json +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/tsconfig.integration.json +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/extension/tsconfig.json +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/release-please-config.json +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/Makefile +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/bughunt.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/_gen.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/dup_run.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/editsave.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/editsave_crlf.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/empty_cells.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/header.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/imageorder.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/input_hang.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/kerneldeath.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/mdcell.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/one_cell.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/rerun.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/runall_error.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/runall_md.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/bughunt/two_cell.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/crlf_mixed.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/crlf_string_marker.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/empty_cells.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/magics_markdown.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/mixed_indent.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/module_header.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/no_final_newline.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/corpus/string_marker.py +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/demo_reconnect.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/lib.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/record_demo.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/shot.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/shotlsp.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v1.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v10.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v11.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v12.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v13.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v14.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v15.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v16.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v17.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v18.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v19.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v2.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v20.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v21.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v22.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v23.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v24.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v26.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v27.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v28.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v29.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v3.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v30.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v31.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v32.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v33.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v34.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v35.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v37.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v38.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v4.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v40.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v41.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v42.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v43.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v44.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v45.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v46.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v47.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v48.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v49.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v5.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v50.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v51.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v52.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v53.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v54.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v55.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v56.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v57.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v58.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v59.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v6.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v60.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v7.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v8.sh +0 -0
- {tithon-0.2.2 → tithon-0.2.3}/scripts/v9.sh +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Commits that only reformat. `git blame` skips these so it lands on the
|
|
2
|
+
# commit that last changed the code, not the one that moved the whitespace.
|
|
3
|
+
#
|
|
4
|
+
# Enable locally with:
|
|
5
|
+
# git config blame.ignoreRevsFile .git-blame-ignore-revs
|
|
6
|
+
# (GitHub honours this file automatically.)
|
|
7
|
+
|
|
8
|
+
# style: format the tree with ruff and biome
|
|
9
|
+
f6c1838afe7dc977d6f08e8b65f548db1f1091d3
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"[python]": {
|
|
3
|
+
"editor.defaultFormatter": "charliermarsh.ruff",
|
|
4
|
+
"editor.formatOnSave": true,
|
|
5
|
+
"editor.codeActionsOnSave": {
|
|
6
|
+
"source.organizeImports.ruff": "explicit"
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
"[typescript]": {
|
|
10
|
+
"editor.defaultFormatter": "biomejs.biome",
|
|
11
|
+
"editor.formatOnSave": true,
|
|
12
|
+
"editor.codeActionsOnSave": {
|
|
13
|
+
"source.organizeImports.biome": "explicit"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"[javascript]": {
|
|
17
|
+
"editor.defaultFormatter": "biomejs.biome",
|
|
18
|
+
"editor.formatOnSave": true
|
|
19
|
+
},
|
|
20
|
+
"[json]": {
|
|
21
|
+
"editor.defaultFormatter": "biomejs.biome",
|
|
22
|
+
"editor.formatOnSave": true
|
|
23
|
+
},
|
|
24
|
+
"[jsonc]": {
|
|
25
|
+
"editor.defaultFormatter": "biomejs.biome",
|
|
26
|
+
"editor.formatOnSave": true
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.3](https://github.com/rnoro/tithon/compare/v0.2.2...v0.2.3) (2026-08-16)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **extension:** let "open as Notebook" stick, per file ([08ba8c1](https://github.com/rnoro/tithon/commit/08ba8c157988a027edcdd71ee5be831b703ed48b))
|
|
9
|
+
* share cell outputs through the project, not the journal ([1ba9d24](https://github.com/rnoro/tithon/commit/1ba9d24a7612bbc530a40da007517d4315be7651))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* clear the lint backlog and undo two formatter regressions ([7cd4e10](https://github.com/rnoro/tithon/commit/7cd4e107269ca735d145cb9e2cf8b6b51346ff68))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Documentation
|
|
18
|
+
|
|
19
|
+
* fix guide for Windows in readme ([bd77e14](https://github.com/rnoro/tithon/commit/bd77e14dd4a39c871a476d1139fc5191736c475e))
|
|
20
|
+
* state invariants instead of naming the ledger ([35e4913](https://github.com/rnoro/tithon/commit/35e4913e696817d4bddd67ff8c7861bf54401aea))
|
|
21
|
+
|
|
3
22
|
## [0.2.2](https://github.com/rnoro/tithon/compare/v0.2.1...v0.2.2) (2026-08-12)
|
|
4
23
|
|
|
5
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: tithon
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Tithon - The immortal Python REPL that will set you free.
|
|
5
5
|
Project-URL: Homepage, https://github.com/rnoro/tithon
|
|
6
6
|
Project-URL: Documentation, https://tithon.readthedocs.io/
|
|
@@ -105,7 +105,8 @@ moves it to the host.
|
|
|
105
105
|
remote, connect over a Tunnel or Remote-SSH — the notebook then works exactly
|
|
106
106
|
as it does locally.
|
|
107
107
|
|
|
108
|
-
> Windows
|
|
108
|
+
> On Windows, we recommend running Tithon inside WSL and connecting with VS Code using the WSL extension.
|
|
109
|
+
> Native Windows is not currently supported.
|
|
109
110
|
|
|
110
111
|
## Install
|
|
111
112
|
|
|
@@ -241,6 +242,32 @@ Outputs live in `$TITHON_HOME/sessions/<session>/journal.db` (raw messages plus
|
|
|
241
242
|
folded snapshots), with rich outputs written as files under
|
|
242
243
|
`<workdir>/.tithon/outputs/` and referenced from the journal.
|
|
243
244
|
|
|
245
|
+
### Sharing a notebook's outputs
|
|
246
|
+
|
|
247
|
+
A percent-format `.py` holds only code, and the journal above is machine-local
|
|
248
|
+
(binary, unbounded, unmergeable). So alongside it the daemon keeps the _folded_
|
|
249
|
+
output state as text in your project:
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
<project>/.tithon/
|
|
253
|
+
cells/<relpath>.json # what each cell currently shows
|
|
254
|
+
outputs/ # its images, sha256-deduplicated
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Commit that directory and whoever clones the repository opens the file with your
|
|
258
|
+
results already in it — what `.ipynb` gives you, without the outputs living in
|
|
259
|
+
the `.py`. Images are referenced rather than embedded, so a plot redrawn every
|
|
260
|
+
step of a training loop still commits one file, not one per frame. Leave the
|
|
261
|
+
directory uncommitted (or `.gitignore` it) to keep your outputs to yourself;
|
|
262
|
+
nothing else depends on it, and your own session restores from the journal
|
|
263
|
+
either way.
|
|
264
|
+
|
|
265
|
+
Terminating a kernel yourself (`tithon kill`, or **Tithon: Terminate Kernel…**)
|
|
266
|
+
means you are done with that session, so reopening the file no longer restores
|
|
267
|
+
its cells. The history is kept — **Tithon: Restore Previous Outputs** brings it
|
|
268
|
+
back. Every involuntary loss (daemon restart, host reboot, dropped tunnel, idle
|
|
269
|
+
GC) still restores automatically.
|
|
270
|
+
|
|
244
271
|
## License
|
|
245
272
|
|
|
246
273
|
[MIT](LICENSE).
|
|
@@ -53,7 +53,8 @@ moves it to the host.
|
|
|
53
53
|
remote, connect over a Tunnel or Remote-SSH — the notebook then works exactly
|
|
54
54
|
as it does locally.
|
|
55
55
|
|
|
56
|
-
> Windows
|
|
56
|
+
> On Windows, we recommend running Tithon inside WSL and connecting with VS Code using the WSL extension.
|
|
57
|
+
> Native Windows is not currently supported.
|
|
57
58
|
|
|
58
59
|
## Install
|
|
59
60
|
|
|
@@ -189,6 +190,32 @@ Outputs live in `$TITHON_HOME/sessions/<session>/journal.db` (raw messages plus
|
|
|
189
190
|
folded snapshots), with rich outputs written as files under
|
|
190
191
|
`<workdir>/.tithon/outputs/` and referenced from the journal.
|
|
191
192
|
|
|
193
|
+
### Sharing a notebook's outputs
|
|
194
|
+
|
|
195
|
+
A percent-format `.py` holds only code, and the journal above is machine-local
|
|
196
|
+
(binary, unbounded, unmergeable). So alongside it the daemon keeps the _folded_
|
|
197
|
+
output state as text in your project:
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
<project>/.tithon/
|
|
201
|
+
cells/<relpath>.json # what each cell currently shows
|
|
202
|
+
outputs/ # its images, sha256-deduplicated
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Commit that directory and whoever clones the repository opens the file with your
|
|
206
|
+
results already in it — what `.ipynb` gives you, without the outputs living in
|
|
207
|
+
the `.py`. Images are referenced rather than embedded, so a plot redrawn every
|
|
208
|
+
step of a training loop still commits one file, not one per frame. Leave the
|
|
209
|
+
directory uncommitted (or `.gitignore` it) to keep your outputs to yourself;
|
|
210
|
+
nothing else depends on it, and your own session restores from the journal
|
|
211
|
+
either way.
|
|
212
|
+
|
|
213
|
+
Terminating a kernel yourself (`tithon kill`, or **Tithon: Terminate Kernel…**)
|
|
214
|
+
means you are done with that session, so reopening the file no longer restores
|
|
215
|
+
its cells. The history is kept — **Tithon: Restore Previous Outputs** brings it
|
|
216
|
+
back. Every involuntary loss (daemon restart, host reboot, dropped tunnel, idle
|
|
217
|
+
GC) still restores automatically.
|
|
218
|
+
|
|
192
219
|
## License
|
|
193
220
|
|
|
194
221
|
[MIT](LICENSE).
|
|
@@ -261,7 +261,9 @@ image / widget / text output below it as native notebook rendering. Outputs come
|
|
|
261
261
|
from the journal and are attached to cells, so the `.py` is never polluted.
|
|
262
262
|
|
|
263
263
|
`.py` files open as **plain text by default**; Notebook is opt-in (command
|
|
264
|
-
_Open as Notebook_), and you can flip back with _Open as Text Editor_.
|
|
264
|
+
_Open as Notebook_), and you can flip back with _Open as Text Editor_. For a
|
|
265
|
+
durable per-file choice, _Always Open With…_ offers exactly _Text Editor_ and
|
|
266
|
+
_Notebook_ from the Explorer context menu and both editor representations.
|
|
265
267
|
|
|
266
268
|
- **Byte-exact round-trip is mandatory.** Serialization preserves the user's
|
|
267
269
|
formatting, whitespace, and comments to the byte — no auto-reformat
|
|
@@ -342,20 +344,57 @@ drives the same daemon over the socket:
|
|
|
342
344
|
## 6. On-disk layout
|
|
343
345
|
|
|
344
346
|
```
|
|
345
|
-
$TITHON_HOME (default ~/.tithon)/
|
|
347
|
+
$TITHON_HOME (default ~/.tithon)/ # machine-local; never in a repo
|
|
346
348
|
daemon.sock # unix socket (0600)
|
|
347
349
|
daemon.pid
|
|
348
350
|
daemon.log
|
|
349
351
|
sessions/<session-dir>/
|
|
350
352
|
meta.json
|
|
353
|
+
kernel.json # carries an hmac-sha256 key
|
|
351
354
|
journal.db # SQLite (WAL): executions, messages, artifacts
|
|
352
355
|
|
|
353
|
-
<workdir>/.tithon/
|
|
354
|
-
|
|
356
|
+
<workdir>/.tithon/ # the document's output state; shareable
|
|
357
|
+
outputs/ # rich-output files, sha256-deduplicated
|
|
358
|
+
exec{N}_{idx}_{sha8}.png
|
|
359
|
+
cells/<relpath>.json # folded snapshot per source file
|
|
355
360
|
```
|
|
356
361
|
|
|
357
362
|
The `.tithon/outputs/` location is configurable (default: inside the workspace).
|
|
358
363
|
|
|
364
|
+
**What lives where, and why.** The journal is this machine's verbatim
|
|
365
|
+
write-ahead record — binary, WAL, unbounded, rewritten on every run — so it can
|
|
366
|
+
neither be committed nor merged, and it sits in `$TITHON_HOME` beside the kernel
|
|
367
|
+
connection file whose hmac key must never reach a repository.
|
|
368
|
+
|
|
369
|
+
What a *reader* of a shared notebook needs is not that record but the **fold**:
|
|
370
|
+
the current output state per execution. The daemon projects it onto
|
|
371
|
+
`.tithon/cells/<relpath>.json` (stable key order, one field per line). Cloning
|
|
372
|
+
the project therefore restores the outputs — the one property `.ipynb` has that
|
|
373
|
+
a percent-format `.py` does not — while images stay as deduplicated files rather
|
|
374
|
+
than one base64 blob per frame, so a live-updating plot commits **one** file.
|
|
375
|
+
|
|
376
|
+
It is published once per **user action** — when a submitted batch drains, or a
|
|
377
|
+
clear lands — not once per cell: rebuilding it re-serializes every execution's
|
|
378
|
+
fold, so per-cell writes would make a Run All quadratic in the notebook's
|
|
379
|
+
length. The shared file therefore lags a running batch by design; that is sound
|
|
380
|
+
because it is a projection of a journal that already holds everything, and a
|
|
381
|
+
daemon that dies mid-batch republishes when `_recover_inflight` terminalizes the
|
|
382
|
+
cell it was on. A publish that fails (read-only checkout, full disk) also
|
|
383
|
+
suppresses the artifact reclaim that would otherwise follow a clear, so the
|
|
384
|
+
shared file never names an image that has already been deleted.
|
|
385
|
+
|
|
386
|
+
The journal stays authoritative for the machine that ran the cells: a sidecar is
|
|
387
|
+
imported only into a session with no local executions of its own, and an imported
|
|
388
|
+
execution is terminal, message-less, and has its fold hydrated from the stored
|
|
389
|
+
snapshot (`ExecutionFold.hydrate`) so the startup artifact sweep counts its
|
|
390
|
+
images as live instead of reclaiming them.
|
|
391
|
+
|
|
392
|
+
Nothing machine-specific is written. A cell's origin carries its index and range
|
|
393
|
+
but no uri, and execution ids are renumbered on import — the file is tracked,
|
|
394
|
+
hand-editable and merge-prone, so its ids are data rather than keys, and each row
|
|
395
|
+
is rebound to the reading file's own uri (which the sidecar's location already
|
|
396
|
+
implies) so that per-file restore scoping keeps it.
|
|
397
|
+
|
|
359
398
|
---
|
|
360
399
|
|
|
361
400
|
## 7. Tricky points & how they are handled
|
|
@@ -479,7 +518,7 @@ make core # v1–v4 v47 v49 v50 v57 core journal / daemon lifecycle
|
|
|
479
518
|
make serializer # v6 percent <-> notebook round-trip
|
|
480
519
|
make backpressure# v9 slow-client host protection
|
|
481
520
|
make widgets # v5 v29 v30 ipywidget mirror + render + live animation
|
|
482
|
-
make restore # v7 v8 v15 v16 v22 v38
|
|
521
|
+
make restore # v7 v8 v15 v16 v22 v38 v61 v62 v63 reconnect restore, orphan, cloned repo, closed session
|
|
483
522
|
make livesync # v10–v14 v33 v37 live streaming into cells
|
|
484
523
|
make kernels # v17–v21 v23 v24 v26 v40 v45 per-file kernels + lifecycle + idle-GC
|
|
485
524
|
make richoutputs # v27 v28 v31 v34 v35 matplotlib/tqdm images, live-plot GC, clear, storage
|
|
@@ -506,6 +545,8 @@ Capability → what it guarantees → how it is verified:
|
|
|
506
545
|
| Bounded render cost | Coalescing caps UI updates | `liveSync.test.ts` (50k events → 1 sink call) |
|
|
507
546
|
| Host protection | Slow client can't grow memory or block others | `test_backpressure.py`, `v9` |
|
|
508
547
|
| Widget rendering | Widgets render in VSCode, restore, and animate live | `v29` (static + restore), `v30` (live) |
|
|
548
|
+
| Shared outputs | A cloned repo restores outputs + images | `v61` (real `git clone`), `test_sidecar.py` |
|
|
549
|
+
| Deliberate close | A killed session is not re-seeded; history kept | `v62` (daemon), `v63` (real VSCode seed gate) |
|
|
509
550
|
|
|
510
551
|
`make vscode` downloads VSCode and needs system libraries (Debian/Ubuntu):
|
|
511
552
|
|
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.2.3](https://github.com/rnoro/tithon/compare/vscode-v0.2.2...vscode-v0.2.3) (2026-08-16)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **extension:** confirm destructive kernel actions; notify outcomes ([73c6d13](https://github.com/rnoro/tithon/commit/73c6d13fcece4630b675cb28d0e5d6e34a317527))
|
|
9
|
+
* **extension:** let "open as Notebook" stick, per file ([08ba8c1](https://github.com/rnoro/tithon/commit/08ba8c157988a027edcdd71ee5be831b703ed48b))
|
|
10
|
+
* **extension:** let "open as Notebook" stick, per file ([d921f52](https://github.com/rnoro/tithon/commit/d921f52e6a0a9f7033adea41b110c5ecc8c10c5f))
|
|
11
|
+
* share cell outputs through the project, not the journal ([1ba9d24](https://github.com/rnoro/tithon/commit/1ba9d24a7612bbc530a40da007517d4315be7651))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* clear the lint backlog and undo two formatter regressions ([7cd4e10](https://github.com/rnoro/tithon/commit/7cd4e107269ca735d145cb9e2cf8b6b51346ff68))
|
|
17
|
+
* **extension:** serialize durable editor choice ([376ae78](https://github.com/rnoro/tithon/commit/376ae786c296d71b3473dba9efdc04c637bc9854))
|
|
18
|
+
|
|
3
19
|
## [0.2.2](https://github.com/rnoro/tithon/compare/vscode-v0.2.1...vscode-v0.2.2) (2026-08-12)
|
|
4
20
|
|
|
5
21
|
|
|
@@ -107,6 +107,10 @@ stays pure source — outputs never touch the file, so diffs stay clean.
|
|
|
107
107
|
time, with no manual command.
|
|
108
108
|
- **ipywidgets** — `tqdm` bars and interactive widgets render through a bundled
|
|
109
109
|
widget renderer and come back at their real state, not their initial value.
|
|
110
|
+
- **Shareable outputs** — the folded output state is kept as text in
|
|
111
|
+
`<project>/.tithon/` (images referenced as deduplicated files, not embedded).
|
|
112
|
+
Commit it and whoever clones the repository opens the file with your results
|
|
113
|
+
already in it; leave it uncommitted to keep them to yourself.
|
|
110
114
|
|
|
111
115
|
## Commands
|
|
112
116
|
|
|
@@ -115,15 +119,27 @@ The rest are run from the command palette or the notebook's kernel toolbar:
|
|
|
115
119
|
|
|
116
120
|
| Command | What it does |
|
|
117
121
|
| --- | --- |
|
|
118
|
-
| `Tithon: Open as Notebook` / `Open as Text Editor` | Toggle a `.py` between notebook and plain text. |
|
|
122
|
+
| `Tithon: Open as Notebook` / `Open as Text Editor` | Toggle a `.py` between notebook and plain text, once. |
|
|
123
|
+
| `Tithon: Always Open With…` | Choose Text Editor or Notebook for this one file, permanently in this workspace. |
|
|
119
124
|
| `Tithon: Restart Kernel` | Restart the session's kernel. |
|
|
120
125
|
| `Tithon: Interrupt Kernel` | Interrupt the running cell. |
|
|
121
126
|
| `Tithon: Select Python Interpreter` | Choose the interpreter the daemon runs the kernel as. |
|
|
122
127
|
| `Tithon: Restart Daemon` | Restart the host daemon. |
|
|
123
|
-
| `Tithon: Terminate Kernel…` | Kill the session's kernel. |
|
|
128
|
+
| `Tithon: Terminate Kernel…` | Kill the session's kernel. Reopening the file then leaves the cells empty — terminating means you are done with that session. |
|
|
129
|
+
| `Tithon: Restore Previous Outputs` | Put a terminated session's outputs back into the cells. |
|
|
124
130
|
|
|
125
131
|
`Run Cell` is offered as a CodeLens above each `# %%` cell.
|
|
126
132
|
|
|
133
|
+
A `.py` opens as a normal text editor unless you say otherwise. Use `Tithon:
|
|
134
|
+
Always Open With…` from the Explorer context menu, editor title, or Notebook
|
|
135
|
+
toolbar to choose `Text Editor` or `Notebook`. Tithon records the choice as one
|
|
136
|
+
`workbench.editorAssociations` entry in the workspace's `.vscode/settings.json`,
|
|
137
|
+
so it survives reloads and can be committed for the team. If you want *every*
|
|
138
|
+
`.py` in a workspace to open as a notebook, that is VSCode's own setting rather
|
|
139
|
+
than a Tithon command — `Reopen With…` → `Configure default editor…` on a `.py`,
|
|
140
|
+
choosing `Notebook - Tithon`. It writes `"*.py": "tithon-py"`, which applies to
|
|
141
|
+
every Python file in scope, `setup.py` and `conftest.py` included.
|
|
142
|
+
|
|
127
143
|
## Settings
|
|
128
144
|
|
|
129
145
|
| Setting | Default | Purpose |
|
|
@@ -131,6 +147,7 @@ The rest are run from the command palette or the notebook's kernel toolbar:
|
|
|
131
147
|
| `tithon.autoStartDaemon` | `true` | Start the daemon on the host when it isn't already running (spawned detached, so it survives reconnects). |
|
|
132
148
|
| `tithon.daemonCommand` | `tithon` | Command used to launch the daemon (run as `<command> daemon`). Set an absolute path if `tithon` isn't on `PATH`. |
|
|
133
149
|
| `tithon.pythonPath` | `""` | Run the daemon as `<python> -m tithon daemon`. Leave empty to use the Python extension's selected interpreter. |
|
|
150
|
+
| `tithon.confirmDestructiveActions` | `true` | Ask in a modal dialog before Restart Kernel, Terminate Kernel and Restart Daemon. Set to `false` if you restart often and accept losing the namespace to a mis-click. |
|
|
134
151
|
| `tithon.kernelIdleTimeout` | `0` | Reap a kernel after this many seconds idle (no attached notebook, nothing running or queued). Outputs stay restorable from the journal; only the in-memory variables are lost. `0` = never. Applied when the extension (re)starts the daemon. |
|
|
135
152
|
|
|
136
153
|
## How it works
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://biomejs.dev/schemas/2.5.8/schema.json",
|
|
3
|
+
"files": {
|
|
4
|
+
"includes": ["**", "!dist", "!out-int", "!.vscode-test", "!**/*.vsix", "!test/fixtures"]
|
|
5
|
+
},
|
|
6
|
+
"formatter": {
|
|
7
|
+
"enabled": true,
|
|
8
|
+
"indentStyle": "space",
|
|
9
|
+
"indentWidth": 2,
|
|
10
|
+
"lineWidth": 100
|
|
11
|
+
},
|
|
12
|
+
"javascript": {
|
|
13
|
+
"formatter": {
|
|
14
|
+
"quoteStyle": "double",
|
|
15
|
+
"semicolons": "always",
|
|
16
|
+
"trailingCommas": "all",
|
|
17
|
+
"arrowParentheses": "always"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"linter": {
|
|
21
|
+
"enabled": true,
|
|
22
|
+
"rules": {
|
|
23
|
+
"preset": "recommended",
|
|
24
|
+
"suspicious": {
|
|
25
|
+
"noExplicitAny": "off"
|
|
26
|
+
},
|
|
27
|
+
"style": {
|
|
28
|
+
"noNonNullAssertion": "off"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"assist": {
|
|
33
|
+
"actions": {
|
|
34
|
+
"source": {
|
|
35
|
+
"organizeImports": "on"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* notebook/LSP guard suites against the insiders build as an early warning, so a
|
|
13
13
|
* breaking change is caught before it reaches users on stable.
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
import * as path from "node:path";
|
|
16
17
|
import { runTests } from "@vscode/test-electron";
|
|
17
18
|
|
|
18
19
|
async function main(): Promise<void> {
|
|
@@ -41,9 +42,7 @@ async function main(): Promise<void> {
|
|
|
41
42
|
// Python language servers (ruff/ty) live, so it passes TITHON_LSP_EXT_DIR — a
|
|
42
43
|
// curated extensions dir — and we drop --disable-extensions for that run.
|
|
43
44
|
const lspExtDir = process.env.TITHON_LSP_EXT_DIR;
|
|
44
|
-
const extArgs = lspExtDir
|
|
45
|
-
? [`--extensions-dir=${lspExtDir}`]
|
|
46
|
-
: ["--disable-extensions"];
|
|
45
|
+
const extArgs = lspExtDir ? [`--extensions-dir=${lspExtDir}`] : ["--disable-extensions"];
|
|
47
46
|
|
|
48
47
|
// Default "stable" matches @vscode/test-electron's own default (latest stable),
|
|
49
48
|
// so the existing bundles are unchanged; the insiders bundle overrides it.
|
|
@@ -74,6 +73,11 @@ async function main(): Promise<void> {
|
|
|
74
73
|
TITHON_FIXTURE: process.env.TITHON_FIXTURE ?? "",
|
|
75
74
|
TITHON_HELPER: process.env.TITHON_HELPER ?? "",
|
|
76
75
|
TITHON_SUITE: process.env.TITHON_SUITE ?? "",
|
|
76
|
+
// "1" leaves `tithon.confirmDestructiveActions` at its shipped default, so
|
|
77
|
+
// the suite that verifies the modal gate sees what a user sees. Every other
|
|
78
|
+
// suite drives restart/terminate unattended, so the bootstrap turns it off.
|
|
79
|
+
TITHON_CONFIRM_DESTRUCTIVE: process.env.TITHON_CONFIRM_DESTRUCTIVE ?? "",
|
|
80
|
+
TITHON_CONFIRM_TARGET: process.env.TITHON_CONFIRM_TARGET ?? "",
|
|
77
81
|
},
|
|
78
82
|
});
|
|
79
83
|
}
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* source via the verified SessionClient so daemon cell_hash == the extension's
|
|
5
5
|
* computeCellHash(cellSource), and waits until every execution is terminal.
|
|
6
6
|
*/
|
|
7
|
-
import { readFileSync } from "fs";
|
|
8
|
-
import { parse, cellSource } from "../src/serializer";
|
|
9
|
-
import { SessionClient } from "../src/sessionClient";
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
10
8
|
import { computeCellHash } from "../src/cellAttach";
|
|
9
|
+
import { cellSource, parse } from "../src/serializer";
|
|
10
|
+
import { SessionClient } from "../src/sessionClient";
|
|
11
11
|
|
|
12
12
|
async function main(): Promise<void> {
|
|
13
13
|
const file = process.argv[2];
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Flow: run cell 0 (starts live), then insert a new cell and run it, and assert
|
|
9
9
|
* the new cell shows its output WITHOUT any manual restore step.
|
|
10
10
|
*/
|
|
11
|
-
import * as assert from "assert";
|
|
11
|
+
import * as assert from "node:assert";
|
|
12
12
|
import * as vscode from "vscode";
|
|
13
13
|
|
|
14
14
|
const dec = new TextDecoder();
|
|
@@ -64,7 +64,10 @@ describe("Tithon streams output for a cell added after live started (v14)", () =
|
|
|
64
64
|
const nb = await vscode.workspace.openNotebookDocument(uri);
|
|
65
65
|
await vscode.window.showNotebookDocument(nb);
|
|
66
66
|
await waitFor(() => nb.cellCount >= 1, 15000, "cells");
|
|
67
|
-
await vscode.commands.executeCommand("notebook.selectKernel", {
|
|
67
|
+
await vscode.commands.executeCommand("notebook.selectKernel", {
|
|
68
|
+
id: "tithon",
|
|
69
|
+
extension: ext.id,
|
|
70
|
+
});
|
|
68
71
|
|
|
69
72
|
// Run the first cell — this starts live sync (index has only cell 0).
|
|
70
73
|
await runCell(uri, 0);
|
|
@@ -8,30 +8,41 @@
|
|
|
8
8
|
* command. Auto-open must (a) restore the lines already produced and (b) keep
|
|
9
9
|
* appending new lines as the loop runs.
|
|
10
10
|
*/
|
|
11
|
-
import * as assert from "assert";
|
|
11
|
+
import * as assert from "node:assert";
|
|
12
|
+
import { readFileSync } from "node:fs";
|
|
12
13
|
import * as vscode from "vscode";
|
|
13
|
-
import { readFileSync } from "fs";
|
|
14
|
-
import { parse, cellSource } from "../../src/serializer";
|
|
15
|
-
import { SessionClient } from "../../src/sessionClient";
|
|
16
14
|
import { computeCellHash } from "../../src/cellAttach";
|
|
15
|
+
import { cellSource, parse } from "../../src/serializer";
|
|
16
|
+
import { SessionClient } from "../../src/sessionClient";
|
|
17
17
|
|
|
18
18
|
const dec = new TextDecoder();
|
|
19
19
|
function cellText(cell: vscode.NotebookCell): string {
|
|
20
20
|
let s = "";
|
|
21
|
-
for (const o of cell.outputs)
|
|
22
|
-
|
|
21
|
+
for (const o of cell.outputs)
|
|
22
|
+
for (const it of o.items)
|
|
23
|
+
if (it.mime.includes("stdout") || it.mime === "text/plain") s += dec.decode(it.data);
|
|
23
24
|
return s;
|
|
24
25
|
}
|
|
25
26
|
function lines(t: string): number[] {
|
|
26
|
-
return t
|
|
27
|
+
return t
|
|
28
|
+
.split("\n")
|
|
29
|
+
.map((x) => x.trim())
|
|
30
|
+
.filter((x) => /^\d+$/.test(x))
|
|
31
|
+
.map(Number);
|
|
27
32
|
}
|
|
28
33
|
async function waitFor(pred: () => boolean, ms: number, label: string): Promise<void> {
|
|
29
34
|
const deadline = Date.now() + ms;
|
|
30
|
-
while (!pred()) {
|
|
35
|
+
while (!pred()) {
|
|
36
|
+
if (Date.now() > deadline) throw new Error(`timed out: ${label}`);
|
|
37
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
38
|
+
}
|
|
31
39
|
}
|
|
32
40
|
function ext(): vscode.Extension<unknown> {
|
|
33
41
|
const e = vscode.extensions.all.find((x) =>
|
|
34
|
-
(x.packageJSON?.contributes?.commands ?? []).some(
|
|
42
|
+
(x.packageJSON?.contributes?.commands ?? []).some(
|
|
43
|
+
(c: { command?: string }) => c.command === "tithon.restartKernel",
|
|
44
|
+
),
|
|
45
|
+
);
|
|
35
46
|
if (!e) throw new Error("Tithon extension not found");
|
|
36
47
|
return e;
|
|
37
48
|
}
|
|
@@ -43,12 +54,17 @@ describe("Tithon auto-restore + live on open, no command (v22)", () => {
|
|
|
43
54
|
|
|
44
55
|
// Driver starts the long loop on this file's kernel (independent of the UI).
|
|
45
56
|
const cells = parse(readFileSync(uri.fsPath, "utf8")).cells;
|
|
46
|
-
const loopIdx = cells.findIndex(
|
|
57
|
+
const loopIdx = cells.findIndex(
|
|
58
|
+
(c) => c.kind === "code" && c.body.some((l) => l.text.includes("range(30)")),
|
|
59
|
+
);
|
|
47
60
|
assert.ok(loopIdx >= 0, "fixture needs the range(30) loop");
|
|
48
61
|
const src = cellSource(cells[loopIdx]);
|
|
49
62
|
const driver = new SessionClient(undefined, uri.toString());
|
|
50
63
|
await driver.execute(src, {
|
|
51
|
-
uri: uri.toString(),
|
|
64
|
+
uri: uri.toString(),
|
|
65
|
+
range: { start: 0, end: 0 },
|
|
66
|
+
cell_hash: computeCellHash(src),
|
|
67
|
+
index: loopIdx,
|
|
52
68
|
});
|
|
53
69
|
|
|
54
70
|
// Let a few lines accumulate so there is real prior output to auto-restore.
|
|
@@ -66,15 +82,25 @@ describe("Tithon auto-restore + live on open, no command (v22)", () => {
|
|
|
66
82
|
const nb = await vscode.workspace.openNotebookDocument(uri);
|
|
67
83
|
await vscode.window.showNotebookDocument(nb);
|
|
68
84
|
await waitFor(() => nb.cellCount >= 1, 15000, "cells");
|
|
69
|
-
await vscode.commands.executeCommand("notebook.selectKernel", {
|
|
85
|
+
await vscode.commands.executeCommand("notebook.selectKernel", {
|
|
86
|
+
id: "tithon",
|
|
87
|
+
extension: ext().id,
|
|
88
|
+
});
|
|
70
89
|
|
|
71
90
|
// (a) prior output restored: at least the early lines show up.
|
|
72
|
-
await waitFor(
|
|
91
|
+
await waitFor(
|
|
92
|
+
() => lines(cellText(nb.cellAt(loopIdx))).length >= 4,
|
|
93
|
+
20000,
|
|
94
|
+
"auto-restored prior output",
|
|
95
|
+
);
|
|
73
96
|
const restoredMax = Math.max(...lines(cellText(nb.cellAt(loopIdx))));
|
|
74
97
|
|
|
75
98
|
// (b) live continues: the cell keeps growing past what was there at open.
|
|
76
|
-
await waitFor(
|
|
77
|
-
|
|
99
|
+
await waitFor(
|
|
100
|
+
() => Math.max(...lines(cellText(nb.cellAt(loopIdx))), -1) > restoredMax,
|
|
101
|
+
25000,
|
|
102
|
+
"live output continued after open",
|
|
103
|
+
);
|
|
78
104
|
|
|
79
105
|
const final = lines(cellText(nb.cellAt(loopIdx)));
|
|
80
106
|
assert.ok(final.length >= 5, `expected continuous output, got ${JSON.stringify(final)}`);
|
|
@@ -4,26 +4,33 @@
|
|
|
4
4
|
* (tithon.autoStartDaemon) and stream output — "pip install tithon, then just
|
|
5
5
|
* use it". Also asserts the kernel reports its Python version (label plumbing).
|
|
6
6
|
*/
|
|
7
|
-
import * as assert from "assert";
|
|
7
|
+
import * as assert from "node:assert";
|
|
8
|
+
import * as fs from "node:fs";
|
|
9
|
+
import * as path from "node:path";
|
|
8
10
|
import * as vscode from "vscode";
|
|
9
|
-
import * as fs from "fs";
|
|
10
|
-
import * as path from "path";
|
|
11
11
|
import { SessionClient } from "../../src/sessionClient";
|
|
12
12
|
|
|
13
13
|
const dec = new TextDecoder();
|
|
14
14
|
function cellText(cell: vscode.NotebookCell): string {
|
|
15
15
|
let s = "";
|
|
16
|
-
for (const o of cell.outputs)
|
|
17
|
-
|
|
16
|
+
for (const o of cell.outputs)
|
|
17
|
+
for (const it of o.items)
|
|
18
|
+
if (it.mime.includes("stdout") || it.mime === "text/plain") s += dec.decode(it.data);
|
|
18
19
|
return s;
|
|
19
20
|
}
|
|
20
21
|
async function waitFor(pred: () => boolean, ms: number, label: string): Promise<void> {
|
|
21
22
|
const deadline = Date.now() + ms;
|
|
22
|
-
while (!pred()) {
|
|
23
|
+
while (!pred()) {
|
|
24
|
+
if (Date.now() > deadline) throw new Error(`timed out: ${label}`);
|
|
25
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
26
|
+
}
|
|
23
27
|
}
|
|
24
28
|
function ext(): vscode.Extension<unknown> {
|
|
25
29
|
const e = vscode.extensions.all.find((x) =>
|
|
26
|
-
(x.packageJSON?.contributes?.commands ?? []).some(
|
|
30
|
+
(x.packageJSON?.contributes?.commands ?? []).some(
|
|
31
|
+
(c: { command?: string }) => c.command === "tithon.restartKernel",
|
|
32
|
+
),
|
|
33
|
+
);
|
|
27
34
|
if (!e) throw new Error("Tithon extension not found");
|
|
28
35
|
return e;
|
|
29
36
|
}
|
|
@@ -39,20 +46,29 @@ describe("Tithon daemon auto-start (v23)", () => {
|
|
|
39
46
|
// Use the interpreter path (Jupyter-style `<python> -m tithon`) — no venv
|
|
40
47
|
// activation, no `tithon` on PATH. daemonCommand stays default "tithon"
|
|
41
48
|
// (absent here) to prove the interpreter candidate is what starts it.
|
|
42
|
-
await vscode.workspace
|
|
49
|
+
await vscode.workspace
|
|
50
|
+
.getConfiguration("tithon")
|
|
43
51
|
.update("pythonPath", process.env.TITHON_PYTHON!, vscode.ConfigurationTarget.Global);
|
|
44
52
|
|
|
45
53
|
const nb = await vscode.workspace.openNotebookDocument(uri);
|
|
46
54
|
await vscode.window.showNotebookDocument(nb);
|
|
47
55
|
await waitFor(() => nb.cellCount >= 1, 15000, "cells");
|
|
48
56
|
// Selecting the kernel triggers ensureLive -> ensureDaemon (auto-start).
|
|
49
|
-
await vscode.commands.executeCommand("notebook.selectKernel", {
|
|
57
|
+
await vscode.commands.executeCommand("notebook.selectKernel", {
|
|
58
|
+
id: "tithon",
|
|
59
|
+
extension: ext().id,
|
|
60
|
+
});
|
|
50
61
|
await vscode.commands.executeCommand("notebook.cell.execute", {
|
|
51
|
-
ranges: [new vscode.NotebookRange(0, 1)],
|
|
62
|
+
ranges: [new vscode.NotebookRange(0, 1)],
|
|
63
|
+
document: uri,
|
|
52
64
|
});
|
|
53
65
|
|
|
54
66
|
// Output only appears if the daemon was actually auto-started.
|
|
55
|
-
await waitFor(
|
|
67
|
+
await waitFor(
|
|
68
|
+
() => cellText(nb.cellAt(0)).includes("AUTO_OK"),
|
|
69
|
+
40000,
|
|
70
|
+
"auto-started daemon streamed output",
|
|
71
|
+
);
|
|
56
72
|
assert.ok(fs.existsSync(pidFile), "daemon.pid should exist after auto-start");
|
|
57
73
|
|
|
58
74
|
// Kernel reports its Python version (for the "Tithon · Python x.y" label).
|
|
@@ -60,7 +76,10 @@ describe("Tithon daemon auto-start (v23)", () => {
|
|
|
60
76
|
await c.attach(0);
|
|
61
77
|
const py = c.kernelInfo()?.python ?? "";
|
|
62
78
|
c.close();
|
|
63
|
-
assert.ok(
|
|
79
|
+
assert.ok(
|
|
80
|
+
/^\d+\.\d+/.test(py),
|
|
81
|
+
`kernel should report a python version, got ${JSON.stringify(py)}`,
|
|
82
|
+
);
|
|
64
83
|
console.log(`[v23] daemon auto-started; kernel python = ${py}`);
|
|
65
84
|
});
|
|
66
85
|
});
|