zbook 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 (79) hide show
  1. zbook-0.1.0/.editorconfig +11 -0
  2. zbook-0.1.0/.gitattributes +1 -0
  3. zbook-0.1.0/.github/workflows/release.yml +115 -0
  4. zbook-0.1.0/.gitignore +9 -0
  5. zbook-0.1.0/LICENSE +21 -0
  6. zbook-0.1.0/PKG-INFO +170 -0
  7. zbook-0.1.0/README.md +146 -0
  8. zbook-0.1.0/frontend/index.html +13 -0
  9. zbook-0.1.0/frontend/package-lock.json +2819 -0
  10. zbook-0.1.0/frontend/package.json +35 -0
  11. zbook-0.1.0/frontend/public/font-licenses.txt +98 -0
  12. zbook-0.1.0/frontend/src/App.tsx +1874 -0
  13. zbook-0.1.0/frontend/src/components/CellEditor.tsx +132 -0
  14. zbook-0.1.0/frontend/src/components/CodexPanel.tsx +1261 -0
  15. zbook-0.1.0/frontend/src/components/CommandPalette.tsx +164 -0
  16. zbook-0.1.0/frontend/src/components/EnvironmentPanel.tsx +206 -0
  17. zbook-0.1.0/frontend/src/components/FileTree.tsx +201 -0
  18. zbook-0.1.0/frontend/src/components/Notebook.tsx +375 -0
  19. zbook-0.1.0/frontend/src/components/icons.tsx +81 -0
  20. zbook-0.1.0/frontend/src/editor/theme.ts +66 -0
  21. zbook-0.1.0/frontend/src/main.tsx +14 -0
  22. zbook-0.1.0/frontend/src/model/notebook.ts +143 -0
  23. zbook-0.1.0/frontend/src/model/notebookTools.ts +178 -0
  24. zbook-0.1.0/frontend/src/services/contents.ts +120 -0
  25. zbook-0.1.0/frontend/src/services/environment.ts +75 -0
  26. zbook-0.1.0/frontend/src/services/http.ts +76 -0
  27. zbook-0.1.0/frontend/src/services/kernel.ts +272 -0
  28. zbook-0.1.0/frontend/src/styles.css +781 -0
  29. zbook-0.1.0/frontend/src/vite-env.d.ts +1 -0
  30. zbook-0.1.0/frontend/tsconfig.json +21 -0
  31. zbook-0.1.0/frontend/vite.config.ts +17 -0
  32. zbook-0.1.0/pyproject.toml +60 -0
  33. zbook-0.1.0/src/zbook/__init__.py +24 -0
  34. zbook-0.1.0/src/zbook/__main__.py +4 -0
  35. zbook-0.1.0/src/zbook/app.py +210 -0
  36. zbook-0.1.0/src/zbook/cli.py +383 -0
  37. zbook-0.1.0/src/zbook/codex.py +446 -0
  38. zbook-0.1.0/src/zbook/codex_handler.py +655 -0
  39. zbook-0.1.0/src/zbook/config.py +79 -0
  40. zbook-0.1.0/src/zbook/environments.py +160 -0
  41. zbook-0.1.0/src/zbook/handlers.py +229 -0
  42. zbook-0.1.0/src/zbook/kernel_spec.py +84 -0
  43. zbook-0.1.0/src/zbook/static/assets/index-whrSZ2Mg.js +118 -0
  44. zbook-0.1.0/src/zbook/static/assets/index-xmz5a47X.css +1 -0
  45. zbook-0.1.0/src/zbook/static/assets/inter-cyrillic-ext-wght-italic-B5xAaiFk.woff2 +0 -0
  46. zbook-0.1.0/src/zbook/static/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
  47. zbook-0.1.0/src/zbook/static/assets/inter-cyrillic-wght-italic-DzZdc28x.woff2 +0 -0
  48. zbook-0.1.0/src/zbook/static/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
  49. zbook-0.1.0/src/zbook/static/assets/inter-greek-ext-wght-italic-DcOpz6Lw.woff2 +0 -0
  50. zbook-0.1.0/src/zbook/static/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
  51. zbook-0.1.0/src/zbook/static/assets/inter-greek-wght-italic-CILZdfAp.woff2 +0 -0
  52. zbook-0.1.0/src/zbook/static/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
  53. zbook-0.1.0/src/zbook/static/assets/inter-latin-ext-wght-italic-0pjOp8NU.woff2 +0 -0
  54. zbook-0.1.0/src/zbook/static/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
  55. zbook-0.1.0/src/zbook/static/assets/inter-latin-wght-italic-DpCbqKDY.woff2 +0 -0
  56. zbook-0.1.0/src/zbook/static/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
  57. zbook-0.1.0/src/zbook/static/assets/inter-vietnamese-wght-italic-K3WlGtc8.woff2 +0 -0
  58. zbook-0.1.0/src/zbook/static/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
  59. zbook-0.1.0/src/zbook/static/assets/jetbrains-mono-cyrillic-wght-italic-CfQkWpeR.woff2 +0 -0
  60. zbook-0.1.0/src/zbook/static/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
  61. zbook-0.1.0/src/zbook/static/assets/jetbrains-mono-greek-wght-italic-Dmq-fBVQ.woff2 +0 -0
  62. zbook-0.1.0/src/zbook/static/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
  63. zbook-0.1.0/src/zbook/static/assets/jetbrains-mono-latin-ext-wght-italic-BrDczivE.woff2 +0 -0
  64. zbook-0.1.0/src/zbook/static/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  65. zbook-0.1.0/src/zbook/static/assets/jetbrains-mono-latin-wght-italic-B2M6KQje.woff2 +0 -0
  66. zbook-0.1.0/src/zbook/static/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  67. zbook-0.1.0/src/zbook/static/assets/jetbrains-mono-vietnamese-wght-italic-Dcombn6O.woff2 +0 -0
  68. zbook-0.1.0/src/zbook/static/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
  69. zbook-0.1.0/src/zbook/static/font-licenses.txt +98 -0
  70. zbook-0.1.0/src/zbook/static/index.html +14 -0
  71. zbook-0.1.0/src/zbook/uv_env.py +185 -0
  72. zbook-0.1.0/tests/smoke_test.py +78 -0
  73. zbook-0.1.0/tests/test_cli.py +257 -0
  74. zbook-0.1.0/tests/test_codex_protocol.py +316 -0
  75. zbook-0.1.0/tests/test_config.py +68 -0
  76. zbook-0.1.0/tests/test_environments.py +81 -0
  77. zbook-0.1.0/tests/test_handlers.py +16 -0
  78. zbook-0.1.0/tests/test_uv_env.py +58 -0
  79. zbook-0.1.0/uv.lock +1232 -0
@@ -0,0 +1,11 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ indent_style = space
8
+ indent_size = 2
9
+
10
+ [*.py]
11
+ indent_size = 4
@@ -0,0 +1 @@
1
+ src/zbook/static/assets/* -diff linguist-generated=true
@@ -0,0 +1,115 @@
1
+ name: Publish release to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v[0-9]+.[0-9]+.[0-9]+"
7
+ - "v[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
8
+ - "v[0-9]+.[0-9]+.[0-9]+[ab][0-9]+"
9
+
10
+ concurrency:
11
+ group: pypi-${{ github.ref }}
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ build:
16
+ name: Build and verify distributions
17
+ runs-on: ubuntu-latest
18
+ permissions:
19
+ contents: read
20
+ steps:
21
+ - name: Check out source
22
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
+ with:
24
+ persist-credentials: false
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
28
+ with:
29
+ enable-cache: false
30
+ version: "0.12.5"
31
+
32
+ - name: Install Node.js
33
+ uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
34
+ with:
35
+ node-version: 24
36
+ cache: npm
37
+ cache-dependency-path: frontend/package-lock.json
38
+
39
+ - name: Verify release tag
40
+ shell: bash
41
+ run: |
42
+ package_version="$(uv version --short)"
43
+ if [[ "v${package_version}" != "${GITHUB_REF_NAME}" ]]; then
44
+ echo "::error::Tag ${GITHUB_REF_NAME} does not match package version ${package_version}"
45
+ exit 1
46
+ fi
47
+
48
+ - name: Install Python dependencies
49
+ run: uv sync --locked --dev
50
+
51
+ - name: Check Python
52
+ run: uv run ruff check .
53
+
54
+ - name: Test Python
55
+ run: uv run pytest -q
56
+
57
+ - name: Build web client
58
+ working-directory: frontend
59
+ run: |
60
+ npm ci
61
+ npm run build
62
+
63
+ - name: Verify committed web client
64
+ shell: bash
65
+ run: |
66
+ if [[ -n "$(git status --porcelain -- src/zbook/static)" ]]; then
67
+ git status --short -- src/zbook/static
68
+ echo "::error::Frontend build output is not committed"
69
+ exit 1
70
+ fi
71
+
72
+ - name: Build wheel and source distribution
73
+ run: uv build --no-sources
74
+
75
+ - name: Smoke-test wheel
76
+ run: uv run --isolated --no-project --with dist/*.whl tests/smoke_test.py
77
+
78
+ - name: Smoke-test source distribution
79
+ run: uv run --isolated --no-project --with dist/*.tar.gz tests/smoke_test.py
80
+
81
+ - name: Upload distributions
82
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
83
+ with:
84
+ name: distributions
85
+ path: dist/
86
+ if-no-files-found: error
87
+ retention-days: 7
88
+
89
+ publish:
90
+ name: Publish to PyPI
91
+ needs: build
92
+ runs-on: ubuntu-latest
93
+ environment:
94
+ name: pypi
95
+ url: https://pypi.org/project/zbook/
96
+ permissions:
97
+ id-token: write
98
+ steps:
99
+ - name: Install uv
100
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
101
+ with:
102
+ enable-cache: false
103
+ version: "0.12.5"
104
+
105
+ - name: Download distributions
106
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
107
+ with:
108
+ name: distributions
109
+ path: dist/
110
+
111
+ - name: Generate publish attestations
112
+ uses: astral-sh/attest-action@f589a42a7efb6fe400b4f400de60b4bc90390027 # v0.0.6
113
+
114
+ - name: Publish distributions
115
+ run: uv publish --trusted-publishing always dist/*
zbook-0.1.0/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ .venv/
2
+ tmp/
3
+ .pytest_cache/
4
+ .ruff_cache/
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.egg-info/
8
+ dist/
9
+ frontend/node_modules/
zbook-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zbook contributors
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.
zbook-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,170 @@
1
+ Metadata-Version: 2.5
2
+ Name: zbook
3
+ Version: 0.1.0
4
+ Summary: A small, keyboard-first notebook with uv and Codex integration
5
+ Project-URL: Homepage, https://github.com/honglu2875/zbook
6
+ Project-URL: Repository, https://github.com/honglu2875/zbook
7
+ Project-URL: Issues, https://github.com/honglu2875/zbook/issues
8
+ Author: honglu2875
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: codex,ipython,jupyter,notebook,uv
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Web Environment
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Topic :: Scientific/Engineering
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: jupyter-server<3,>=2.15
21
+ Requires-Dist: nbformat<6,>=5.10
22
+ Requires-Dist: traitlets<6,>=5.14
23
+ Description-Content-Type: text/markdown
24
+
25
+ # Zbook
26
+
27
+ Zbook is an intentionally small, keyboard-first notebook application. It keeps the useful core of Jupyter—real `.ipynb` files, IPython kernels, markdown, rich outputs, and a workspace tree—then adds a first-class local Codex panel and a focused `uv` environment workflow.
28
+
29
+ The design target is closer to Zed than JupyterLab: flat surfaces, restrained color, minimal persistent chrome, fast keyboard navigation, and no extension ecosystem to carry.
30
+
31
+ ## Working checkpoint
32
+
33
+ The main notebook loop is functional:
34
+
35
+ - the file tree is served by Jupyter's Contents API and is rooted at the configured workspace;
36
+ - notebooks can be created, opened in closable tabs, renamed inline by double-clicking a tab, deleted, uploaded, autosaved, and exported as `.ipynb`;
37
+ - open tabs, the active notebook, selected cell, panel visibility, and Vim preference are restored per workspace;
38
+ - `Ctrl/Cmd-P` opens a workspace file picker and `Ctrl/Cmd-Shift-P` opens the command palette;
39
+ - the workspace and Codex panes are draggable, keyboard-resizable, and remember their widths across reloads;
40
+ - refreshing the workspace also reloads the active notebook from disk (after confirming before discarding local unsaved changes);
41
+ - folders can be selected and created, and arbitrary files can be uploaded;
42
+ - code cells execute on a real IPython kernel with streamed text, errors, HTML, and PNG output;
43
+ - Markdown cells render in place; code and Markdown editors have syntax highlighting, bundled JetBrains Mono typography, and optional Vim bindings; the UI and prose use bundled Inter;
44
+ - long outputs can be height-limited from the gutter without shrinking their code, scaled images expand to their native resolution on double-click with two-axis scrolling, and `#@title …` gives a code cell a dedicated title row above its execution gutter and a whole-cell collapse toggle; these view preferences persist per workspace without changing the notebook file;
45
+ - **Run all**, execution counts, interrupt, and keyboard execution commands work;
46
+ - the environment panel lists packages and installs or uninstalls them through serialized `uv` operations;
47
+ - a fresh launch defaults to a scratch uv environment under `/tmp`, prepares `ipykernel`, and removes the scratch environment on shutdown;
48
+ - workspace `.venv` folders are detected and can be selected live; a project folder or uv-venv path can also be entered manually;
49
+ - the Codex panel uses the locally signed-in Codex CLI and ChatGPT subscription—no application API key—and streams turns through Codex App Server;
50
+ - Codex receives optional notebook/cell context and exposes live command/file activity plus any required approvals;
51
+ - Codex gets dedicated read/lock/apply cell tools: the read response advertises the current action inventory, relevant cells become visibly read-only across the full reasoning-and-editing turn, remaining locks release automatically at turn end, and edits are revision-checked, atomic, undoable, and saved without a shell/edit/refresh round trip; source-light reads plus `move_after` and `swap` operations make reordering inexpensive;
52
+ - each Codex cell edit gets an in-notebook review marker and a safe one-step undo until the notebook changes again;
53
+ - the Codex pane reads the installed CLI's model catalog and subscription rate limits, defaults to GPT-5.6-Luna with medium reasoning when available, and provides model/effort pickers, quota refresh, sign-in, and sign-out.
54
+ - Zbook-created Codex threads persist through App Server, are remembered per workspace, and can be resumed from the compact thread switcher with command/file/notebook activity restored and Zbook's private context augmentation kept out of the visible transcript.
55
+
56
+ This is still a focused checkpoint, not a JupyterLab replacement. Tabs share one workspace kernel and save before switching; non-notebook files are managed but not edited; and Jupyter widgets and arbitrary JavaScript outputs are not supported.
57
+
58
+ ## Architecture
59
+
60
+ ```text
61
+ React + CodeMirror 6
62
+ ├─ Jupyter Contents / Kernel WebSocket APIs
63
+ ├─ Zbook package-management API ── uv ── selected .venv
64
+ └─ Zbook Codex WebSocket ── codex app-server (stdio JSONL)
65
+ └─ dynamic cell tools ── revision-locked React notebook state
66
+
67
+ Jupyter Server ExtensionApp
68
+ ├─ file boundary: configured workspace
69
+ ├─ kernel: exact <venv>/bin/python
70
+ └─ static production frontend
71
+ ```
72
+
73
+ Python owns processes, filesystem boundaries, and Jupyter integration. TypeScript owns interaction state and rendering. The selected notebook environment is deliberately separate from the app's own environment so installing a package cannot destabilize the server. Codex runs with workspace-write scope, while commands that need broader filesystem or network access still use the CLI's approval flow. The bridge follows the official [Codex App Server](https://developers.openai.com/codex/app-server) protocol over a private authenticated WebSocket.
74
+
75
+ ## Run the checks
76
+
77
+ ```bash
78
+ uv run ruff check src tests
79
+ uv run pytest -q
80
+ cd frontend && npm run build
81
+ ```
82
+
83
+ ## Build the web client
84
+
85
+ Use Node.js 20.19 or newer:
86
+
87
+ ```bash
88
+ cd frontend
89
+ npm install
90
+ npm run build
91
+ ```
92
+
93
+ The Vite build is emitted into `src/zbook/static/`, where the Python application serves it.
94
+
95
+ ## Install and launch
96
+
97
+ Build the web client once, then install the local package as a uv tool:
98
+
99
+ ```bash
100
+ uv sync --dev
101
+ cd frontend && npm install && npm run build && cd ..
102
+ uv tool install .
103
+ ```
104
+
105
+ The installed command has a small preflight check and a dedicated launch command:
106
+
107
+ ```bash
108
+ zbook check
109
+ zbook run
110
+ zbook run --workspace-dir /absolute/path/to/workspace
111
+ zbook run --ip 0.0.0.0 --port 8888
112
+ ```
113
+
114
+ `zbook run` uses the current directory as its workspace and listens only on Jupyter's `localhost` default. Binding a wildcard or non-loopback address prints a highlighted security warning: remote clients that obtain access can execute notebook code and reach the selected workspace and Codex. `0.0.0.0` listens on every network interface, though actual reachability still depends on the host firewall and network configuration. Keep Jupyter authentication enabled.
115
+
116
+ The default kernel environment is a disposable uv venv under `/tmp`; a persistent uv environment can be selected from the environment panel while the app is running.
117
+
118
+ Jupyter Server options go after a `--` passthrough boundary:
119
+
120
+ ```bash
121
+ zbook run --workspace-dir /absolute/path/to/workspace --port 8890 -- \
122
+ --ServerApp.open_browser=False
123
+ ```
124
+
125
+ Startup environment traits can be passed the same way when needed:
126
+
127
+ ```bash
128
+ zbook run --workspace-dir /absolute/path/to/workspace -- \
129
+ --ZbookApp.venv=/absolute/path/to/project/.venv
130
+ ```
131
+
132
+ For compatibility, Jupyter flags supplied without `--` are still forwarded, but Zbook prints a highlighted warning showing the preferred form. The old direct form (`zbook --ZbookApp.workspace=…`) also remains available with a migration warning. During development, prefix these commands with `uv run`, such as `uv run zbook check`.
133
+
134
+ ## Releasing
135
+
136
+ Releases are built and published by `.github/workflows/release.yml` through PyPI Trusted Publishing. The PyPI publisher must match the `honglu2875/zbook` repository, the `release.yml` workflow, and the `pypi` GitHub environment.
137
+
138
+ For the first release, tag the current `0.1.0` commit after configuring the `pypi` environment and pending PyPI publisher:
139
+
140
+ ```bash
141
+ git tag -a v0.1.0 -m "zbook 0.1.0"
142
+ git push origin v0.1.0
143
+ ```
144
+
145
+ For subsequent releases, update the sole package-version source in `pyproject.toml`, review the lockfile, commit, and push the matching tag:
146
+
147
+ ```bash
148
+ uv version 0.1.1
149
+ git add pyproject.toml uv.lock
150
+ git commit -m "Release 0.1.1"
151
+ git tag -a v0.1.1 -m "zbook 0.1.1"
152
+ git push origin main v0.1.1
153
+ ```
154
+
155
+ The workflow rejects a tag that does not match the package version, rebuilds and verifies the committed web client, tests both distribution formats in isolated environments, and grants the publishing credential only to the final PyPI job. Published PyPI versions cannot be replaced; use a new version for every changed release.
156
+
157
+ ## Notebook key model
158
+
159
+ - `Shift-Escape` leaves an editor and enters notebook navigation mode.
160
+ - `j` / `k` or the arrow keys move between cells in navigation mode.
161
+ - `Enter` or `i` edits the selected cell.
162
+ - `a` inserts a code cell above; `b` or `o` inserts one below. Hover or keyboard-focus the space between cells to choose Code or Markdown explicitly.
163
+ - `Ctrl-Enter` runs in place, `Shift-Enter` runs and advances, and `Alt-Enter` runs and inserts.
164
+ - Vim bindings can be toggled from the status bar. Vim receives its keymap before the standard CodeMirror keymaps.
165
+
166
+ This two-level model avoids the classic conflict between Vim's modes and notebook-level commands: notebook navigation is a separate outer mode, and Vim operates only inside the active editor.
167
+
168
+ ## License
169
+
170
+ Zbook is released under the [MIT License](LICENSE). The bundled Inter and JetBrains Mono fonts remain under the SIL Open Font License 1.1; their [notices](frontend/public/font-licenses.txt) ship with the frontend.
zbook-0.1.0/README.md ADDED
@@ -0,0 +1,146 @@
1
+ # Zbook
2
+
3
+ Zbook is an intentionally small, keyboard-first notebook application. It keeps the useful core of Jupyter—real `.ipynb` files, IPython kernels, markdown, rich outputs, and a workspace tree—then adds a first-class local Codex panel and a focused `uv` environment workflow.
4
+
5
+ The design target is closer to Zed than JupyterLab: flat surfaces, restrained color, minimal persistent chrome, fast keyboard navigation, and no extension ecosystem to carry.
6
+
7
+ ## Working checkpoint
8
+
9
+ The main notebook loop is functional:
10
+
11
+ - the file tree is served by Jupyter's Contents API and is rooted at the configured workspace;
12
+ - notebooks can be created, opened in closable tabs, renamed inline by double-clicking a tab, deleted, uploaded, autosaved, and exported as `.ipynb`;
13
+ - open tabs, the active notebook, selected cell, panel visibility, and Vim preference are restored per workspace;
14
+ - `Ctrl/Cmd-P` opens a workspace file picker and `Ctrl/Cmd-Shift-P` opens the command palette;
15
+ - the workspace and Codex panes are draggable, keyboard-resizable, and remember their widths across reloads;
16
+ - refreshing the workspace also reloads the active notebook from disk (after confirming before discarding local unsaved changes);
17
+ - folders can be selected and created, and arbitrary files can be uploaded;
18
+ - code cells execute on a real IPython kernel with streamed text, errors, HTML, and PNG output;
19
+ - Markdown cells render in place; code and Markdown editors have syntax highlighting, bundled JetBrains Mono typography, and optional Vim bindings; the UI and prose use bundled Inter;
20
+ - long outputs can be height-limited from the gutter without shrinking their code, scaled images expand to their native resolution on double-click with two-axis scrolling, and `#@title …` gives a code cell a dedicated title row above its execution gutter and a whole-cell collapse toggle; these view preferences persist per workspace without changing the notebook file;
21
+ - **Run all**, execution counts, interrupt, and keyboard execution commands work;
22
+ - the environment panel lists packages and installs or uninstalls them through serialized `uv` operations;
23
+ - a fresh launch defaults to a scratch uv environment under `/tmp`, prepares `ipykernel`, and removes the scratch environment on shutdown;
24
+ - workspace `.venv` folders are detected and can be selected live; a project folder or uv-venv path can also be entered manually;
25
+ - the Codex panel uses the locally signed-in Codex CLI and ChatGPT subscription—no application API key—and streams turns through Codex App Server;
26
+ - Codex receives optional notebook/cell context and exposes live command/file activity plus any required approvals;
27
+ - Codex gets dedicated read/lock/apply cell tools: the read response advertises the current action inventory, relevant cells become visibly read-only across the full reasoning-and-editing turn, remaining locks release automatically at turn end, and edits are revision-checked, atomic, undoable, and saved without a shell/edit/refresh round trip; source-light reads plus `move_after` and `swap` operations make reordering inexpensive;
28
+ - each Codex cell edit gets an in-notebook review marker and a safe one-step undo until the notebook changes again;
29
+ - the Codex pane reads the installed CLI's model catalog and subscription rate limits, defaults to GPT-5.6-Luna with medium reasoning when available, and provides model/effort pickers, quota refresh, sign-in, and sign-out.
30
+ - Zbook-created Codex threads persist through App Server, are remembered per workspace, and can be resumed from the compact thread switcher with command/file/notebook activity restored and Zbook's private context augmentation kept out of the visible transcript.
31
+
32
+ This is still a focused checkpoint, not a JupyterLab replacement. Tabs share one workspace kernel and save before switching; non-notebook files are managed but not edited; and Jupyter widgets and arbitrary JavaScript outputs are not supported.
33
+
34
+ ## Architecture
35
+
36
+ ```text
37
+ React + CodeMirror 6
38
+ ├─ Jupyter Contents / Kernel WebSocket APIs
39
+ ├─ Zbook package-management API ── uv ── selected .venv
40
+ └─ Zbook Codex WebSocket ── codex app-server (stdio JSONL)
41
+ └─ dynamic cell tools ── revision-locked React notebook state
42
+
43
+ Jupyter Server ExtensionApp
44
+ ├─ file boundary: configured workspace
45
+ ├─ kernel: exact <venv>/bin/python
46
+ └─ static production frontend
47
+ ```
48
+
49
+ Python owns processes, filesystem boundaries, and Jupyter integration. TypeScript owns interaction state and rendering. The selected notebook environment is deliberately separate from the app's own environment so installing a package cannot destabilize the server. Codex runs with workspace-write scope, while commands that need broader filesystem or network access still use the CLI's approval flow. The bridge follows the official [Codex App Server](https://developers.openai.com/codex/app-server) protocol over a private authenticated WebSocket.
50
+
51
+ ## Run the checks
52
+
53
+ ```bash
54
+ uv run ruff check src tests
55
+ uv run pytest -q
56
+ cd frontend && npm run build
57
+ ```
58
+
59
+ ## Build the web client
60
+
61
+ Use Node.js 20.19 or newer:
62
+
63
+ ```bash
64
+ cd frontend
65
+ npm install
66
+ npm run build
67
+ ```
68
+
69
+ The Vite build is emitted into `src/zbook/static/`, where the Python application serves it.
70
+
71
+ ## Install and launch
72
+
73
+ Build the web client once, then install the local package as a uv tool:
74
+
75
+ ```bash
76
+ uv sync --dev
77
+ cd frontend && npm install && npm run build && cd ..
78
+ uv tool install .
79
+ ```
80
+
81
+ The installed command has a small preflight check and a dedicated launch command:
82
+
83
+ ```bash
84
+ zbook check
85
+ zbook run
86
+ zbook run --workspace-dir /absolute/path/to/workspace
87
+ zbook run --ip 0.0.0.0 --port 8888
88
+ ```
89
+
90
+ `zbook run` uses the current directory as its workspace and listens only on Jupyter's `localhost` default. Binding a wildcard or non-loopback address prints a highlighted security warning: remote clients that obtain access can execute notebook code and reach the selected workspace and Codex. `0.0.0.0` listens on every network interface, though actual reachability still depends on the host firewall and network configuration. Keep Jupyter authentication enabled.
91
+
92
+ The default kernel environment is a disposable uv venv under `/tmp`; a persistent uv environment can be selected from the environment panel while the app is running.
93
+
94
+ Jupyter Server options go after a `--` passthrough boundary:
95
+
96
+ ```bash
97
+ zbook run --workspace-dir /absolute/path/to/workspace --port 8890 -- \
98
+ --ServerApp.open_browser=False
99
+ ```
100
+
101
+ Startup environment traits can be passed the same way when needed:
102
+
103
+ ```bash
104
+ zbook run --workspace-dir /absolute/path/to/workspace -- \
105
+ --ZbookApp.venv=/absolute/path/to/project/.venv
106
+ ```
107
+
108
+ For compatibility, Jupyter flags supplied without `--` are still forwarded, but Zbook prints a highlighted warning showing the preferred form. The old direct form (`zbook --ZbookApp.workspace=…`) also remains available with a migration warning. During development, prefix these commands with `uv run`, such as `uv run zbook check`.
109
+
110
+ ## Releasing
111
+
112
+ Releases are built and published by `.github/workflows/release.yml` through PyPI Trusted Publishing. The PyPI publisher must match the `honglu2875/zbook` repository, the `release.yml` workflow, and the `pypi` GitHub environment.
113
+
114
+ For the first release, tag the current `0.1.0` commit after configuring the `pypi` environment and pending PyPI publisher:
115
+
116
+ ```bash
117
+ git tag -a v0.1.0 -m "zbook 0.1.0"
118
+ git push origin v0.1.0
119
+ ```
120
+
121
+ For subsequent releases, update the sole package-version source in `pyproject.toml`, review the lockfile, commit, and push the matching tag:
122
+
123
+ ```bash
124
+ uv version 0.1.1
125
+ git add pyproject.toml uv.lock
126
+ git commit -m "Release 0.1.1"
127
+ git tag -a v0.1.1 -m "zbook 0.1.1"
128
+ git push origin main v0.1.1
129
+ ```
130
+
131
+ The workflow rejects a tag that does not match the package version, rebuilds and verifies the committed web client, tests both distribution formats in isolated environments, and grants the publishing credential only to the final PyPI job. Published PyPI versions cannot be replaced; use a new version for every changed release.
132
+
133
+ ## Notebook key model
134
+
135
+ - `Shift-Escape` leaves an editor and enters notebook navigation mode.
136
+ - `j` / `k` or the arrow keys move between cells in navigation mode.
137
+ - `Enter` or `i` edits the selected cell.
138
+ - `a` inserts a code cell above; `b` or `o` inserts one below. Hover or keyboard-focus the space between cells to choose Code or Markdown explicitly.
139
+ - `Ctrl-Enter` runs in place, `Shift-Enter` runs and advances, and `Alt-Enter` runs and inserts.
140
+ - Vim bindings can be toggled from the status bar. Vim receives its keymap before the standard CodeMirror keymaps.
141
+
142
+ This two-level model avoids the classic conflict between Vim's modes and notebook-level commands: notebook navigation is a separate outer mode, and Vim operates only inside the active editor.
143
+
144
+ ## License
145
+
146
+ Zbook is released under the [MIT License](LICENSE). The bundled Inter and JetBrains Mono fonts remain under the SIL Open Font License 1.1; their [notices](frontend/public/font-licenses.txt) ship with the frontend.
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="theme-color" content="#17191b" />
7
+ <title>Zbook</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>