tithon 0.1.0__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.
Files changed (147) hide show
  1. tithon-0.1.0/.gitattributes +4 -0
  2. tithon-0.1.0/.gitignore +66 -0
  3. tithon-0.1.0/CHANGELOG.md +15 -0
  4. tithon-0.1.0/LICENSE +21 -0
  5. tithon-0.1.0/PKG-INFO +312 -0
  6. tithon-0.1.0/README.md +260 -0
  7. tithon-0.1.0/docs/SPEC.md +466 -0
  8. tithon-0.1.0/extension/.vscodeignore +9 -0
  9. tithon-0.1.0/extension/CHANGELOG.md +3 -0
  10. tithon-0.1.0/extension/esbuild.mjs +48 -0
  11. tithon-0.1.0/extension/integration/runTest.ts +68 -0
  12. tithon-0.1.0/extension/integration/seed.ts +70 -0
  13. tithon-0.1.0/extension/integration/suite/addcell.test.ts +92 -0
  14. tithon-0.1.0/extension/integration/suite/autoopen.test.ts +83 -0
  15. tithon-0.1.0/extension/integration/suite/autostart.test.ts +66 -0
  16. tithon-0.1.0/extension/integration/suite/dupcode.test.ts +56 -0
  17. tithon-0.1.0/extension/integration/suite/editedcell.test.ts +80 -0
  18. tithon-0.1.0/extension/integration/suite/editordefault.test.ts +55 -0
  19. tithon-0.1.0/extension/integration/suite/index.ts +25 -0
  20. tithon-0.1.0/extension/integration/suite/interrupt.test.ts +82 -0
  21. tithon-0.1.0/extension/integration/suite/live.test.ts +102 -0
  22. tithon-0.1.0/extension/integration/suite/livedisplay.test.ts +118 -0
  23. tithon-0.1.0/extension/integration/suite/livereconnect.test.ts +93 -0
  24. tithon-0.1.0/extension/integration/suite/lsp.test.ts +165 -0
  25. tithon-0.1.0/extension/integration/suite/multicell.test.ts +91 -0
  26. tithon-0.1.0/extension/integration/suite/opentext.test.ts +134 -0
  27. tithon-0.1.0/extension/integration/suite/opentextshot.test.ts +84 -0
  28. tithon-0.1.0/extension/integration/suite/reconnect.test.ts +97 -0
  29. tithon-0.1.0/extension/integration/suite/reconnectstates.test.ts +99 -0
  30. tithon-0.1.0/extension/integration/suite/reopen.test.ts +70 -0
  31. tithon-0.1.0/extension/integration/suite/restartdaemon.test.ts +85 -0
  32. tithon-0.1.0/extension/integration/suite/restartkernel.test.ts +59 -0
  33. tithon-0.1.0/extension/integration/suite/restore.test.ts +98 -0
  34. tithon-0.1.0/extension/integration/suite/richoutputs.test.ts +96 -0
  35. tithon-0.1.0/extension/integration/suite/runcell.test.ts +77 -0
  36. tithon-0.1.0/extension/integration/suite/screenshot.test.ts +61 -0
  37. tithon-0.1.0/extension/integration/suite/twofiles.test.ts +68 -0
  38. tithon-0.1.0/extension/integration/suite/widget.test.ts +74 -0
  39. tithon-0.1.0/extension/integration/suite/widgetlive.test.ts +72 -0
  40. tithon-0.1.0/extension/package-lock.json +6731 -0
  41. tithon-0.1.0/extension/package.json +176 -0
  42. tithon-0.1.0/extension/src/artifactCache.ts +66 -0
  43. tithon-0.1.0/extension/src/cellAttach.ts +161 -0
  44. tithon-0.1.0/extension/src/codeLens.ts +58 -0
  45. tithon-0.1.0/extension/src/css.d.ts +7 -0
  46. tithon-0.1.0/extension/src/daemonClient.ts +133 -0
  47. tithon-0.1.0/extension/src/daemonProcess.ts +207 -0
  48. tithon-0.1.0/extension/src/extension.ts +281 -0
  49. tithon-0.1.0/extension/src/liveSync.ts +330 -0
  50. tithon-0.1.0/extension/src/notebookSerializer.ts +68 -0
  51. tithon-0.1.0/extension/src/outputFold.ts +175 -0
  52. tithon-0.1.0/extension/src/richOutput.ts +180 -0
  53. tithon-0.1.0/extension/src/serializer.ts +240 -0
  54. tithon-0.1.0/extension/src/sessionClient.ts +473 -0
  55. tithon-0.1.0/extension/src/sessionController.ts +866 -0
  56. tithon-0.1.0/extension/src/widgetRender.ts +134 -0
  57. tithon-0.1.0/extension/src/widgetRendererEntry.ts +113 -0
  58. tithon-0.1.0/extension/test/artifactCache.test.ts +39 -0
  59. tithon-0.1.0/extension/test/cellAttach.test.ts +146 -0
  60. tithon-0.1.0/extension/test/fixtures/tqdm_widget_state.json +377 -0
  61. tithon-0.1.0/extension/test/liveSync.test.ts +314 -0
  62. tithon-0.1.0/extension/test/outputFold.test.ts +76 -0
  63. tithon-0.1.0/extension/test/restore.test.ts +138 -0
  64. tithon-0.1.0/extension/test/richDaemon.test.ts +131 -0
  65. tithon-0.1.0/extension/test/richOutput.test.ts +79 -0
  66. tithon-0.1.0/extension/test/serializer.test.ts +196 -0
  67. tithon-0.1.0/extension/test/setup.ts +41 -0
  68. tithon-0.1.0/extension/test/widget.test.ts +90 -0
  69. tithon-0.1.0/extension/tsconfig.integration.json +17 -0
  70. tithon-0.1.0/extension/tsconfig.json +18 -0
  71. tithon-0.1.0/extension/vitest.config.ts +14 -0
  72. tithon-0.1.0/pyproject.toml +70 -0
  73. tithon-0.1.0/scripts/Makefile +26 -0
  74. tithon-0.1.0/scripts/_check_v1.py +58 -0
  75. tithon-0.1.0/scripts/_check_v2.py +48 -0
  76. tithon-0.1.0/scripts/_check_v3.py +67 -0
  77. tithon-0.1.0/scripts/_check_v5.py +60 -0
  78. tithon-0.1.0/scripts/_clear_client.py +50 -0
  79. tithon-0.1.0/scripts/_lastseq.py +19 -0
  80. tithon-0.1.0/scripts/_stalled_client.py +32 -0
  81. tithon-0.1.0/scripts/_workdir_client.py +38 -0
  82. tithon-0.1.0/scripts/corpus/_gen.py +117 -0
  83. tithon-0.1.0/scripts/corpus/crlf_mixed.py +8 -0
  84. tithon-0.1.0/scripts/corpus/crlf_string_marker.py +6 -0
  85. tithon-0.1.0/scripts/corpus/empty_cells.py +5 -0
  86. tithon-0.1.0/scripts/corpus/magics_markdown.py +10 -0
  87. tithon-0.1.0/scripts/corpus/mixed_indent.py +7 -0
  88. tithon-0.1.0/scripts/corpus/module_header.py +10 -0
  89. tithon-0.1.0/scripts/corpus/no_final_newline.py +5 -0
  90. tithon-0.1.0/scripts/corpus/string_marker.py +8 -0
  91. tithon-0.1.0/scripts/demo_reconnect.sh +38 -0
  92. tithon-0.1.0/scripts/lib.sh +51 -0
  93. tithon-0.1.0/scripts/run_verify.sh +42 -0
  94. tithon-0.1.0/scripts/shot.sh +116 -0
  95. tithon-0.1.0/scripts/v1.sh +31 -0
  96. tithon-0.1.0/scripts/v10.sh +54 -0
  97. tithon-0.1.0/scripts/v11.sh +51 -0
  98. tithon-0.1.0/scripts/v12.sh +52 -0
  99. tithon-0.1.0/scripts/v13.sh +46 -0
  100. tithon-0.1.0/scripts/v14.sh +46 -0
  101. tithon-0.1.0/scripts/v15.sh +48 -0
  102. tithon-0.1.0/scripts/v16.sh +54 -0
  103. tithon-0.1.0/scripts/v17.sh +53 -0
  104. tithon-0.1.0/scripts/v18.sh +39 -0
  105. tithon-0.1.0/scripts/v19.sh +43 -0
  106. tithon-0.1.0/scripts/v2.sh +23 -0
  107. tithon-0.1.0/scripts/v20.sh +41 -0
  108. tithon-0.1.0/scripts/v21.sh +42 -0
  109. tithon-0.1.0/scripts/v22.sh +42 -0
  110. tithon-0.1.0/scripts/v23.sh +40 -0
  111. tithon-0.1.0/scripts/v24.sh +45 -0
  112. tithon-0.1.0/scripts/v25.sh +39 -0
  113. tithon-0.1.0/scripts/v26.sh +43 -0
  114. tithon-0.1.0/scripts/v27.sh +43 -0
  115. tithon-0.1.0/scripts/v28.sh +56 -0
  116. tithon-0.1.0/scripts/v29.sh +47 -0
  117. tithon-0.1.0/scripts/v3.sh +24 -0
  118. tithon-0.1.0/scripts/v30.sh +49 -0
  119. tithon-0.1.0/scripts/v31.sh +89 -0
  120. tithon-0.1.0/scripts/v32.sh +119 -0
  121. tithon-0.1.0/scripts/v33.sh +57 -0
  122. tithon-0.1.0/scripts/v34.sh +87 -0
  123. tithon-0.1.0/scripts/v35.sh +58 -0
  124. tithon-0.1.0/scripts/v36.sh +41 -0
  125. tithon-0.1.0/scripts/v4.sh +51 -0
  126. tithon-0.1.0/scripts/v5.sh +51 -0
  127. tithon-0.1.0/scripts/v6.sh +38 -0
  128. tithon-0.1.0/scripts/v7.sh +43 -0
  129. tithon-0.1.0/scripts/v8.sh +72 -0
  130. tithon-0.1.0/scripts/v9.sh +57 -0
  131. tithon-0.1.0/src/tithon/__init__.py +3 -0
  132. tithon-0.1.0/src/tithon/__main__.py +7 -0
  133. tithon-0.1.0/src/tithon/artifacts.py +91 -0
  134. tithon-0.1.0/src/tithon/cli.py +241 -0
  135. tithon-0.1.0/src/tithon/daemon.py +804 -0
  136. tithon-0.1.0/src/tithon/folding.py +165 -0
  137. tithon-0.1.0/src/tithon/journal.py +228 -0
  138. tithon-0.1.0/src/tithon/kernel.py +121 -0
  139. tithon-0.1.0/src/tithon/widgets.py +92 -0
  140. tithon-0.1.0/test/test_artifacts.py +113 -0
  141. tithon-0.1.0/test/test_backpressure.py +87 -0
  142. tithon-0.1.0/test/test_clear.py +94 -0
  143. tithon-0.1.0/test/test_folding.py +139 -0
  144. tithon-0.1.0/test/test_journal_origin.py +63 -0
  145. tithon-0.1.0/test/test_session_layout.py +43 -0
  146. tithon-0.1.0/test/test_widgets.py +111 -0
  147. tithon-0.1.0/uv.lock +2463 -0
@@ -0,0 +1,4 @@
1
+ # The percent round-trip corpus is byte-exact by design (CRLF, no final
2
+ # newline, trailing whitespace). Never let git normalize their line endings,
3
+ # or scripts/v6.sh's 0-byte-diff guarantee would break on checkout.
4
+ scripts/corpus/*.py -text
@@ -0,0 +1,66 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ build/
7
+ dist/
8
+ *.egg-info/
9
+ .eggs/
10
+ *.egg
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .dmypy.json
14
+ dmypy.json
15
+ .ruff_cache/
16
+ .coverage
17
+ .coverage.*
18
+ coverage.xml
19
+ htmlcov/
20
+ .hypothesis/
21
+ .tox/
22
+ .nox/
23
+ .ipynb_checkpoints/
24
+ .venv/
25
+
26
+ # Node / TypeScript
27
+ node_modules/
28
+ *.tsbuildinfo
29
+ .eslintcache
30
+ *.log
31
+ npm-debug.log*
32
+ yarn-debug.log*
33
+ coverage/
34
+ *.lcov
35
+ .nyc_output
36
+ *.tgz
37
+ .npm
38
+
39
+ # Project
40
+ # tithon daemon state (socket, journal, kernel connection files)
41
+ .tithon/
42
+
43
+ # esbuild output
44
+ dist/
45
+ out-int/
46
+
47
+ # VSCode extension test runner
48
+ .vscode-test/
49
+
50
+ # packaged extension
51
+ *.vsix
52
+
53
+ # screenshot render artifacts during script test
54
+ scripts/screenshots/
55
+
56
+ # daemon startup log (nohup)
57
+ nohup.out
58
+
59
+ # Local Agent
60
+ .claude/
61
+
62
+ # OS
63
+ .DS_Store
64
+ Thumbs.db
65
+ *.swp
66
+ *~
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-06-17
9
+
10
+ ### Added
11
+
12
+ - Initial alpha release of Tithon.
13
+ - Persistent remote interactive Python sessions with loss-free journal.
14
+ - Real-time cell output streaming and widget state mirroring.
15
+ - VSCode extension to sync kernel state losslessly.
tithon-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) [year] [fullname]
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
tithon-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,312 @@
1
+ Metadata-Version: 2.4
2
+ Name: tithon
3
+ Version: 0.1.0
4
+ Summary: Tithon - The immortal Python REPL that will set you free.
5
+ Project-URL: Homepage, https://github.com/rnoro/tithon
6
+ Project-URL: Documentation, https://tithon.readthedocs.io/
7
+ Project-URL: Repository, https://github.com/rnoro/tithon
8
+ Project-URL: Bug Tracker, https://github.com/rnoro/tithon/issues
9
+ Project-URL: Discussions, https://github.com/rnoro/tithon/discussions
10
+ Project-URL: Changelog, https://github.com/rnoro/tithon/blob/main/CHANGELOG.md
11
+ Author-email: rnoro <rnoro5122@gmail.com>
12
+ License: MIT License
13
+
14
+ Copyright (c) [year] [fullname]
15
+
16
+ Permission is hereby granted, free of charge, to any person obtaining a copy
17
+ of this software and associated documentation files (the "Software"), to deal
18
+ in the Software without restriction, including without limitation the rights
19
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20
+ copies of the Software, and to permit persons to whom the Software is
21
+ furnished to do so, subject to the following conditions:
22
+
23
+ The above copyright notice and this permission notice shall be included in all
24
+ copies or substantial portions of the Software.
25
+
26
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32
+ SOFTWARE.
33
+ License-File: LICENSE
34
+ Keywords: interactive,jupyter,kernel,persistent,repl,vscode
35
+ Classifier: Development Status :: 3 - Alpha
36
+ Classifier: Intended Audience :: Developers
37
+ Classifier: Intended Audience :: Science/Research
38
+ Classifier: License :: OSI Approved :: MIT License
39
+ Classifier: Operating System :: OS Independent
40
+ Classifier: Programming Language :: Python :: 3
41
+ Classifier: Programming Language :: Python :: 3.11
42
+ Classifier: Programming Language :: Python :: 3.12
43
+ Classifier: Programming Language :: Python :: 3.13
44
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
45
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
46
+ Classifier: Topic :: Text Processing :: Linguistic
47
+ Requires-Python: >=3.11
48
+ Requires-Dist: ipykernel>=6
49
+ Requires-Dist: jupyter-client>=8
50
+ Requires-Dist: websockets>=12
51
+ Description-Content-Type: text/markdown
52
+
53
+ > ### **Attention!**
54
+ >
55
+ > Currently Tithon is alpha version. It may has lots of bugs and issues.
56
+ > Please report issues when you find any bugs which can help me to develop Tithon.
57
+
58
+ # Tithon
59
+
60
+ **The immortal Python REPL that will set you free.** Tithon keeps an interactive
61
+ Python (Jupyter) kernel running on a remote host independently of any client,
62
+ and losslessly restores cell output, progress, and widget state whenever a
63
+ client (re)connects — close your laptop mid-run, reopen over an SSH/VSCode
64
+ tunnel hours later, and your outputs are still there and still streaming.
65
+
66
+ > The name is from Tithonus of Greek myth, granted immortality but not eternal
67
+ > youth — like a remote kernel that stays alive while its outputs wither the
68
+ > moment the client disconnects. Tithon lifts the curse: _immortality, with
69
+ > eternal youth this time._
70
+
71
+ The authoritative design document is [`docs/SPEC.md`](docs/SPEC.md); it also
72
+ covers current implementation maturity and the verification matrix.
73
+
74
+ ---
75
+
76
+ ## Features
77
+
78
+ - **Kernel persistence.** The kernel is spawned detached (`setsid`) and is not a
79
+ child of the daemon, so it survives daemon restarts, crashes, and disconnects.
80
+ - **Loss-free journal.** Every iopub/shell message is preserved verbatim in a
81
+ SQLite (WAL) journal, plus a per-execution _folded_ snapshot (the current
82
+ display state) for fast reconnects.
83
+ - **Snapshot + delta sync.** Clients attach with a `last_seen_seq` and receive a
84
+ snapshot followed by a monotonic-sequence delta stream — gapless and ordered.
85
+ - **Live streaming with bounded cost.** Output streams to cells _as it runs_;
86
+ rendering is coalesced so a 50,000-iteration loop collapses to a handful of
87
+ UI updates instead of melting the renderer.
88
+ - **Outputs live in the journal, not the file.** A percent-format `.py` stays
89
+ pure source (byte-exact round-trip, clean diffs); outputs are reattached to
90
+ cells by content hash. Rich outputs (images) are stored as files, not base64.
91
+ - **Widget state mirror.** `ipywidgets` comm traffic is folded into a
92
+ `widget-state+json` snapshot — a `tqdm` bar with 50k updates reconnects as a
93
+ single bar, not 50k events.
94
+ - **Host protection.** A slow or stalled client cannot grow daemon memory
95
+ without bound or block other clients; the daemon caps per-subscriber buffers
96
+ and drops clients that fall too far behind (they reconnect and resync).
97
+ - **Unix-socket only.** The daemon binds a `0600` unix domain socket — no TCP.
98
+
99
+ ---
100
+
101
+ ## How it works
102
+
103
+ ```
104
+ VSCode / CLI client Remote Host
105
+ ┌────────────────────┐ ┌───────────────────────────────┐
106
+ │ subscribe(last_seq)│ ── unix sock ── │ tithon daemon │
107
+ │ snapshot + delta │ ◀───0600───── │ ├─ journal (SQLite WAL) │
108
+ │ restore / live │ │ ├─ folded snapshots │
109
+ └────────────────────┘ │ └─ widget mirror │
110
+ │ │ ZMQ (detached) │
111
+ │ ┌─────┴───────┐ │
112
+ │ │ ipykernel │ survives │
113
+ │ └─────────────┘ restarts │
114
+ └───────────────────────────────┘
115
+ ```
116
+
117
+ The daemon owns the kernel and journals everything it emits. Clients never talk
118
+ to the kernel directly — they sync against the journal, so any number of clients
119
+ can connect and disconnect at any time and always converge on the same state.
120
+
121
+ ---
122
+
123
+ ## Requirements
124
+
125
+ - **Python 3.11+** (the daemon and CLI).
126
+ - [**uv**](https://github.com/astral-sh/uv) for environment management.
127
+ - **Node 20+ / npm** — only to build or run the VSCode extension.
128
+
129
+ ---
130
+
131
+ ## Installation
132
+
133
+ ### Daemon + CLI
134
+
135
+ ```bash
136
+ uv sync # create .venv (Python 3.11+), install tithon + dev deps
137
+ ```
138
+
139
+ This puts a `tithon` entry point in `.venv/bin`. Run it with `uv run tithon …`,
140
+ or call `.venv/bin/tithon` directly. Dependencies are managed with
141
+ [uv](https://docs.astral.sh/uv/): runtime deps in `[project.dependencies]`, dev
142
+ and verification deps in `[dependency-groups]`, all pinned by `uv.lock`.
143
+
144
+ ### VSCode extension
145
+
146
+ The extension is not yet on the Marketplace; build it from source and either run
147
+ it in a development host or package it as a `.vsix`:
148
+
149
+ ```bash
150
+ cd extension
151
+ npm install
152
+ npm run build # tsc -> dist/
153
+ npx vsce package # optional: -> tithon-extension-<version>.vsix
154
+ ```
155
+
156
+ Press **F5** in `extension/` to launch an Extension Development Host, or install
157
+ the `.vsix` (Extensions panel ▸ "Install from VSIX…"). For the remote workflow
158
+ this project is built for, see
159
+ [Remote workflow (VSCode tunnel)](#remote-workflow-vscode-tunnel) below; the
160
+ automated integration harness is described in [`docs/SPEC.md`](docs/SPEC.md).
161
+
162
+ ---
163
+
164
+ ## Quickstart(CLI)
165
+
166
+ State (socket, log, journal, artifacts) lives under `TITHON_HOME`, default
167
+ `~/.tithon`.
168
+
169
+ **1. Start the daemon** (it runs in the foreground; background it):
170
+
171
+ ```bash
172
+ tithon daemon &
173
+ tail -f ~/.tithon/daemon.log # optional
174
+ ```
175
+
176
+ **2. Run code** — kernel state persists across calls:
177
+
178
+ ```bash
179
+ tithon run -c 'x = 41'
180
+ tithon run -c 'x += 1; print(x)' # -> 42
181
+ tithon status
182
+ ```
183
+
184
+ **3. Survive a disconnect** — the kernel outlives the daemon, and a reconnect
185
+ restores everything:
186
+
187
+ ```bash
188
+ tithon run -c 'for i in range(3): print("line", i)'
189
+
190
+ pkill -9 -f 'tithon daemon' # kill the daemon; the kernel lives on
191
+ tithon daemon & # restart -> re-attaches the same kernel
192
+
193
+ tithon attach --since 0 --once # full snapshot: the prior output is back
194
+ tithon run -c 'print(x)' # -> 42, kernel state intact
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Quickstart(Remote workflow)
200
+
201
+ This is the workflow Tithon is built for: you edit from a laptop while the kernel
202
+ runs on a remote GPU host and keeps running across your disconnects. With a
203
+ VSCode **Tunnel** (or **Remote-SSH**) connection the VSCode _Extension Host_ runs
204
+ **on the remote host**, so the Tithon extension reaches the daemon's host-local
205
+ unix socket directly — no port forwarding. Your laptop only renders the UI, so
206
+ closing it never stops the work.
207
+
208
+ **On the remote host** — install (see [Installation](#installation)) and:
209
+
210
+ ```bash
211
+ # 1. Start the daemon. It binds $TITHON_HOME/daemon.sock on the host
212
+ # (default ~/.tithon/daemon.sock) and owns the kernel.
213
+ tithon daemon &
214
+
215
+ # 2. Make the extension available to the remote VSCode — package it once...
216
+ cd extension && npm install && npx vsce package # -> tithon-extension-<version>.vsix
217
+ # ...then install the .vsix into the remote VSCode (Extensions ▸ "Install from
218
+ # VSIX…", or `code --install-extension tithon-extension-<version>.vsix`).
219
+ # During development you can instead open extension/ and press F5.
220
+
221
+ # 3. Expose the host to VSCode.
222
+ code tunnel # or connect via Remote-SSH
223
+ ```
224
+
225
+ **From your laptop:**
226
+
227
+ 1. Connect to the host (VSCode ▸ _Connect to Tunnel…_ or _Remote-SSH_) and open
228
+ your project folder.
229
+ 2. Open a percent-format `.py`. Run cells with the **Run Cell** CodeLens, then
230
+ run **Tithon: Start Live Output Sync** to stream output into the cells as it
231
+ is produced.
232
+ 3. Close the laptop or drop the connection — the daemon and kernel keep running
233
+ on the host.
234
+ 4. Reconnect later and run **Tithon: Restore Cell Outputs from Daemon** (or just
235
+ reopen the notebook): the outputs are back and resume streaming live.
236
+
237
+ > **Note.** The daemon and the extension must share `TITHON_HOME` (both default
238
+ > to `~/.tithon` for the same user on the host). Because the Extension Host runs
239
+ > on the host, it uses the host-local socket — no manual forwarding. If you
240
+ > instead run the extension on your laptop against a remote daemon, you must
241
+ > forward the unix socket yourself (e.g. SSH `RemoteForward` or `socat`); that is
242
+ > not the default path.
243
+
244
+ ---
245
+
246
+ ## CLI reference
247
+
248
+ | Command | Description |
249
+ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
250
+ | `tithon daemon` | Run the daemon (foreground). Owns the kernel and serves clients. |
251
+ | `tithon run -c CODE` | Submit code and stream its output. `--no-wait` prints the exec id and exits; `--timeout N` bounds the wait. |
252
+ | `tithon attach` | Stream events as NDJSON. `--since N` sets the resume point; `--once` exits after the backlog sync; `--until-done` exits after the next completion. |
253
+ | `tithon status` | Print session, queue, kernel, and widget-model status. |
254
+
255
+ `attach --since` is the reconnect knob:
256
+
257
+ - `--since 0` — full folded snapshot, then live delta.
258
+ - `--since N` — replay only events after seq `N`, then a `sync` marker, then live.
259
+ - `--since -1` — live only (ignore history).
260
+
261
+ ---
262
+
263
+ ## VSCode extension
264
+
265
+ The extension opens percent-format `.py` files as a notebook (`tithon-py`) and
266
+ talks to the daemon over its unix socket. Commands:
267
+
268
+ | Command | What it does |
269
+ | -------------------------------------------------------------------- | --------------------------------------------------------------------------- |
270
+ | `Tithon: Restore Cell Outputs from Daemon` (`tithon.restoreOutputs`) | Reconnect and restore the journal's folded outputs into the notebook cells. |
271
+ | `Tithon: Start Live Output Sync` (`tithon.startLive`) | Keep a session open and stream output into cells in real time. |
272
+ | `Run Cell` (CodeLens, `tithon.runCell`) | Submit a `# %%` cell's code to the daemon. |
273
+
274
+ Outputs are matched to cells by content hash, so they survive edits and reopens;
275
+ an output whose cell was edited since it ran is flagged stale.
276
+
277
+ ---
278
+
279
+ ## Configuration
280
+
281
+ Environment variables read by the daemon and CLI:
282
+
283
+ | Variable | Default | Purpose |
284
+ | -------------------------- | ----------- | ------------------------------------------------------------------ |
285
+ | `TITHON_HOME` | `~/.tithon` | Root for the socket, log, journal, and artifacts. |
286
+ | `TITHON_SUB_QUEUE_MAX` | `10000` | Max queued events per client before it is dropped (backpressure). |
287
+ | `TITHON_SEND_TIMEOUT` | `10.0` | Seconds a client may stall a send before being dropped. |
288
+ | `TITHON_WRITE_BUFFER_HIGH` | `1048576` | Per-connection send-buffer high-water mark (bounds daemon memory). |
289
+ | `TITHON_SOCK_SNDBUF` | `1048576` | Per-connection kernel socket send buffer. |
290
+ | `TITHON_SUB_POLL` | `0.5` | Interval at which a blocked sender re-checks for drop. |
291
+
292
+ **Where outputs are stored.** A percent `.py` never holds outputs. They live in
293
+ `$TITHON_HOME/sessions/default/journal.db` (raw messages + folded snapshots),
294
+ with rich outputs (images) written as files under `<workdir>/.tithon/outputs/`
295
+ and referenced from the journal.
296
+
297
+ ---
298
+
299
+ ## Architecture invariants
300
+
301
+ These are load-bearing; see [`docs/SPEC.md`](docs/SPEC.md) for the full
302
+ rationale.
303
+
304
+ 1. The kernel is spawned detached and its connection file is persisted, so the
305
+ daemon re-attaches to it after a restart.
306
+ 2. All iopub/shell messages are kept verbatim in SQLite (WAL), with a folded
307
+ per-execution snapshot maintained alongside.
308
+ 3. Client sync is snapshot + delta over a monotonically increasing sequence.
309
+ 4. Rich `image/*` outputs are stored as files, not base64 in the journal.
310
+ 5. The daemon binds a `0600` unix domain socket only — never TCP.
311
+
312
+ ---
tithon-0.1.0/README.md ADDED
@@ -0,0 +1,260 @@
1
+ > ### **Attention!**
2
+ >
3
+ > Currently Tithon is alpha version. It may has lots of bugs and issues.
4
+ > Please report issues when you find any bugs which can help me to develop Tithon.
5
+
6
+ # Tithon
7
+
8
+ **The immortal Python REPL that will set you free.** Tithon keeps an interactive
9
+ Python (Jupyter) kernel running on a remote host independently of any client,
10
+ and losslessly restores cell output, progress, and widget state whenever a
11
+ client (re)connects — close your laptop mid-run, reopen over an SSH/VSCode
12
+ tunnel hours later, and your outputs are still there and still streaming.
13
+
14
+ > The name is from Tithonus of Greek myth, granted immortality but not eternal
15
+ > youth — like a remote kernel that stays alive while its outputs wither the
16
+ > moment the client disconnects. Tithon lifts the curse: _immortality, with
17
+ > eternal youth this time._
18
+
19
+ The authoritative design document is [`docs/SPEC.md`](docs/SPEC.md); it also
20
+ covers current implementation maturity and the verification matrix.
21
+
22
+ ---
23
+
24
+ ## Features
25
+
26
+ - **Kernel persistence.** The kernel is spawned detached (`setsid`) and is not a
27
+ child of the daemon, so it survives daemon restarts, crashes, and disconnects.
28
+ - **Loss-free journal.** Every iopub/shell message is preserved verbatim in a
29
+ SQLite (WAL) journal, plus a per-execution _folded_ snapshot (the current
30
+ display state) for fast reconnects.
31
+ - **Snapshot + delta sync.** Clients attach with a `last_seen_seq` and receive a
32
+ snapshot followed by a monotonic-sequence delta stream — gapless and ordered.
33
+ - **Live streaming with bounded cost.** Output streams to cells _as it runs_;
34
+ rendering is coalesced so a 50,000-iteration loop collapses to a handful of
35
+ UI updates instead of melting the renderer.
36
+ - **Outputs live in the journal, not the file.** A percent-format `.py` stays
37
+ pure source (byte-exact round-trip, clean diffs); outputs are reattached to
38
+ cells by content hash. Rich outputs (images) are stored as files, not base64.
39
+ - **Widget state mirror.** `ipywidgets` comm traffic is folded into a
40
+ `widget-state+json` snapshot — a `tqdm` bar with 50k updates reconnects as a
41
+ single bar, not 50k events.
42
+ - **Host protection.** A slow or stalled client cannot grow daemon memory
43
+ without bound or block other clients; the daemon caps per-subscriber buffers
44
+ and drops clients that fall too far behind (they reconnect and resync).
45
+ - **Unix-socket only.** The daemon binds a `0600` unix domain socket — no TCP.
46
+
47
+ ---
48
+
49
+ ## How it works
50
+
51
+ ```
52
+ VSCode / CLI client Remote Host
53
+ ┌────────────────────┐ ┌───────────────────────────────┐
54
+ │ subscribe(last_seq)│ ── unix sock ── │ tithon daemon │
55
+ │ snapshot + delta │ ◀───0600───── │ ├─ journal (SQLite WAL) │
56
+ │ restore / live │ │ ├─ folded snapshots │
57
+ └────────────────────┘ │ └─ widget mirror │
58
+ │ │ ZMQ (detached) │
59
+ │ ┌─────┴───────┐ │
60
+ │ │ ipykernel │ survives │
61
+ │ └─────────────┘ restarts │
62
+ └───────────────────────────────┘
63
+ ```
64
+
65
+ The daemon owns the kernel and journals everything it emits. Clients never talk
66
+ to the kernel directly — they sync against the journal, so any number of clients
67
+ can connect and disconnect at any time and always converge on the same state.
68
+
69
+ ---
70
+
71
+ ## Requirements
72
+
73
+ - **Python 3.11+** (the daemon and CLI).
74
+ - [**uv**](https://github.com/astral-sh/uv) for environment management.
75
+ - **Node 20+ / npm** — only to build or run the VSCode extension.
76
+
77
+ ---
78
+
79
+ ## Installation
80
+
81
+ ### Daemon + CLI
82
+
83
+ ```bash
84
+ uv sync # create .venv (Python 3.11+), install tithon + dev deps
85
+ ```
86
+
87
+ This puts a `tithon` entry point in `.venv/bin`. Run it with `uv run tithon …`,
88
+ or call `.venv/bin/tithon` directly. Dependencies are managed with
89
+ [uv](https://docs.astral.sh/uv/): runtime deps in `[project.dependencies]`, dev
90
+ and verification deps in `[dependency-groups]`, all pinned by `uv.lock`.
91
+
92
+ ### VSCode extension
93
+
94
+ The extension is not yet on the Marketplace; build it from source and either run
95
+ it in a development host or package it as a `.vsix`:
96
+
97
+ ```bash
98
+ cd extension
99
+ npm install
100
+ npm run build # tsc -> dist/
101
+ npx vsce package # optional: -> tithon-extension-<version>.vsix
102
+ ```
103
+
104
+ Press **F5** in `extension/` to launch an Extension Development Host, or install
105
+ the `.vsix` (Extensions panel ▸ "Install from VSIX…"). For the remote workflow
106
+ this project is built for, see
107
+ [Remote workflow (VSCode tunnel)](#remote-workflow-vscode-tunnel) below; the
108
+ automated integration harness is described in [`docs/SPEC.md`](docs/SPEC.md).
109
+
110
+ ---
111
+
112
+ ## Quickstart(CLI)
113
+
114
+ State (socket, log, journal, artifacts) lives under `TITHON_HOME`, default
115
+ `~/.tithon`.
116
+
117
+ **1. Start the daemon** (it runs in the foreground; background it):
118
+
119
+ ```bash
120
+ tithon daemon &
121
+ tail -f ~/.tithon/daemon.log # optional
122
+ ```
123
+
124
+ **2. Run code** — kernel state persists across calls:
125
+
126
+ ```bash
127
+ tithon run -c 'x = 41'
128
+ tithon run -c 'x += 1; print(x)' # -> 42
129
+ tithon status
130
+ ```
131
+
132
+ **3. Survive a disconnect** — the kernel outlives the daemon, and a reconnect
133
+ restores everything:
134
+
135
+ ```bash
136
+ tithon run -c 'for i in range(3): print("line", i)'
137
+
138
+ pkill -9 -f 'tithon daemon' # kill the daemon; the kernel lives on
139
+ tithon daemon & # restart -> re-attaches the same kernel
140
+
141
+ tithon attach --since 0 --once # full snapshot: the prior output is back
142
+ tithon run -c 'print(x)' # -> 42, kernel state intact
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Quickstart(Remote workflow)
148
+
149
+ This is the workflow Tithon is built for: you edit from a laptop while the kernel
150
+ runs on a remote GPU host and keeps running across your disconnects. With a
151
+ VSCode **Tunnel** (or **Remote-SSH**) connection the VSCode _Extension Host_ runs
152
+ **on the remote host**, so the Tithon extension reaches the daemon's host-local
153
+ unix socket directly — no port forwarding. Your laptop only renders the UI, so
154
+ closing it never stops the work.
155
+
156
+ **On the remote host** — install (see [Installation](#installation)) and:
157
+
158
+ ```bash
159
+ # 1. Start the daemon. It binds $TITHON_HOME/daemon.sock on the host
160
+ # (default ~/.tithon/daemon.sock) and owns the kernel.
161
+ tithon daemon &
162
+
163
+ # 2. Make the extension available to the remote VSCode — package it once...
164
+ cd extension && npm install && npx vsce package # -> tithon-extension-<version>.vsix
165
+ # ...then install the .vsix into the remote VSCode (Extensions ▸ "Install from
166
+ # VSIX…", or `code --install-extension tithon-extension-<version>.vsix`).
167
+ # During development you can instead open extension/ and press F5.
168
+
169
+ # 3. Expose the host to VSCode.
170
+ code tunnel # or connect via Remote-SSH
171
+ ```
172
+
173
+ **From your laptop:**
174
+
175
+ 1. Connect to the host (VSCode ▸ _Connect to Tunnel…_ or _Remote-SSH_) and open
176
+ your project folder.
177
+ 2. Open a percent-format `.py`. Run cells with the **Run Cell** CodeLens, then
178
+ run **Tithon: Start Live Output Sync** to stream output into the cells as it
179
+ is produced.
180
+ 3. Close the laptop or drop the connection — the daemon and kernel keep running
181
+ on the host.
182
+ 4. Reconnect later and run **Tithon: Restore Cell Outputs from Daemon** (or just
183
+ reopen the notebook): the outputs are back and resume streaming live.
184
+
185
+ > **Note.** The daemon and the extension must share `TITHON_HOME` (both default
186
+ > to `~/.tithon` for the same user on the host). Because the Extension Host runs
187
+ > on the host, it uses the host-local socket — no manual forwarding. If you
188
+ > instead run the extension on your laptop against a remote daemon, you must
189
+ > forward the unix socket yourself (e.g. SSH `RemoteForward` or `socat`); that is
190
+ > not the default path.
191
+
192
+ ---
193
+
194
+ ## CLI reference
195
+
196
+ | Command | Description |
197
+ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
198
+ | `tithon daemon` | Run the daemon (foreground). Owns the kernel and serves clients. |
199
+ | `tithon run -c CODE` | Submit code and stream its output. `--no-wait` prints the exec id and exits; `--timeout N` bounds the wait. |
200
+ | `tithon attach` | Stream events as NDJSON. `--since N` sets the resume point; `--once` exits after the backlog sync; `--until-done` exits after the next completion. |
201
+ | `tithon status` | Print session, queue, kernel, and widget-model status. |
202
+
203
+ `attach --since` is the reconnect knob:
204
+
205
+ - `--since 0` — full folded snapshot, then live delta.
206
+ - `--since N` — replay only events after seq `N`, then a `sync` marker, then live.
207
+ - `--since -1` — live only (ignore history).
208
+
209
+ ---
210
+
211
+ ## VSCode extension
212
+
213
+ The extension opens percent-format `.py` files as a notebook (`tithon-py`) and
214
+ talks to the daemon over its unix socket. Commands:
215
+
216
+ | Command | What it does |
217
+ | -------------------------------------------------------------------- | --------------------------------------------------------------------------- |
218
+ | `Tithon: Restore Cell Outputs from Daemon` (`tithon.restoreOutputs`) | Reconnect and restore the journal's folded outputs into the notebook cells. |
219
+ | `Tithon: Start Live Output Sync` (`tithon.startLive`) | Keep a session open and stream output into cells in real time. |
220
+ | `Run Cell` (CodeLens, `tithon.runCell`) | Submit a `# %%` cell's code to the daemon. |
221
+
222
+ Outputs are matched to cells by content hash, so they survive edits and reopens;
223
+ an output whose cell was edited since it ran is flagged stale.
224
+
225
+ ---
226
+
227
+ ## Configuration
228
+
229
+ Environment variables read by the daemon and CLI:
230
+
231
+ | Variable | Default | Purpose |
232
+ | -------------------------- | ----------- | ------------------------------------------------------------------ |
233
+ | `TITHON_HOME` | `~/.tithon` | Root for the socket, log, journal, and artifacts. |
234
+ | `TITHON_SUB_QUEUE_MAX` | `10000` | Max queued events per client before it is dropped (backpressure). |
235
+ | `TITHON_SEND_TIMEOUT` | `10.0` | Seconds a client may stall a send before being dropped. |
236
+ | `TITHON_WRITE_BUFFER_HIGH` | `1048576` | Per-connection send-buffer high-water mark (bounds daemon memory). |
237
+ | `TITHON_SOCK_SNDBUF` | `1048576` | Per-connection kernel socket send buffer. |
238
+ | `TITHON_SUB_POLL` | `0.5` | Interval at which a blocked sender re-checks for drop. |
239
+
240
+ **Where outputs are stored.** A percent `.py` never holds outputs. They live in
241
+ `$TITHON_HOME/sessions/default/journal.db` (raw messages + folded snapshots),
242
+ with rich outputs (images) written as files under `<workdir>/.tithon/outputs/`
243
+ and referenced from the journal.
244
+
245
+ ---
246
+
247
+ ## Architecture invariants
248
+
249
+ These are load-bearing; see [`docs/SPEC.md`](docs/SPEC.md) for the full
250
+ rationale.
251
+
252
+ 1. The kernel is spawned detached and its connection file is persisted, so the
253
+ daemon re-attaches to it after a restart.
254
+ 2. All iopub/shell messages are kept verbatim in SQLite (WAL), with a folded
255
+ per-execution snapshot maintained alongside.
256
+ 3. Client sync is snapshot + delta over a monotonically increasing sequence.
257
+ 4. Rich `image/*` outputs are stored as files, not base64 in the journal.
258
+ 5. The daemon binds a `0600` unix domain socket only — never TCP.
259
+
260
+ ---