hypernote 0.1.2__tar.gz → 0.2.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.
- hypernote-0.2.0/.github/workflows/release.yml +161 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/.gitignore +1 -0
- hypernote-0.2.0/AGENTS.md +188 -0
- hypernote-0.2.0/CHANGELOG.md +97 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/PKG-INFO +39 -8
- {hypernote-0.1.2 → hypernote-0.2.0}/README.md +38 -7
- hypernote-0.2.0/SKILL.md +183 -0
- hypernote-0.2.0/dev/README.md +29 -0
- hypernote-0.2.0/dev/cli-agent-ergonomics-rollout.md +69 -0
- hypernote-0.2.0/dev/current-architecture.md +85 -0
- hypernote-0.2.0/dev/module-map.md +32 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/dev/testing-and-verification.md +1 -1
- hypernote-0.2.0/docs/README.md +22 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/docs/browser-regression-spec.md +27 -1
- hypernote-0.2.0/docs/cli.md +119 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/docs/getting-started.md +30 -0
- hypernote-0.2.0/docs/runtime-model.md +84 -0
- hypernote-0.2.0/docs/sdk.md +114 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/pyproject.toml +5 -1
- {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/cli/main.py +804 -51
- {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/execution_orchestrator.py +79 -2
- {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/runtime_manager.py +41 -3
- {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/sdk.py +387 -27
- hypernote-0.2.0/src/hypernote/server/extension.py +259 -0
- {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/server/handlers.py +119 -7
- hypernote-0.2.0/src/hypernote/server/subshell.py +395 -0
- hypernote-0.2.0/tests/test_browser_regression.py +386 -0
- hypernote-0.2.0/tests/test_cli.py +1157 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/tests/test_live_server.py +24 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/tests/test_runtime_manager.py +22 -1
- {hypernote-0.1.2 → hypernote-0.2.0}/tests/test_sdk.py +60 -0
- hypernote-0.2.0/tests/test_subshell.py +360 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/uv.lock +1 -1
- hypernote-0.1.2/.github/workflows/release.yml +0 -87
- hypernote-0.1.2/AGENTS.md +0 -144
- hypernote-0.1.2/CHANGELOG.md +0 -46
- hypernote-0.1.2/SKILL.md +0 -61
- hypernote-0.1.2/dev/README.md +0 -23
- hypernote-0.1.2/dev/current-architecture.md +0 -30
- hypernote-0.1.2/dev/module-map.md +0 -27
- hypernote-0.1.2/docs/README.md +0 -15
- hypernote-0.1.2/docs/cli.md +0 -62
- hypernote-0.1.2/docs/runtime-model.md +0 -39
- hypernote-0.1.2/docs/sdk.md +0 -82
- hypernote-0.1.2/hypernote/server/extension.py +0 -156
- hypernote-0.1.2/tests/test_browser_regression.py +0 -207
- hypernote-0.1.2/tests/test_cli.py +0 -530
- {hypernote-0.1.2 → hypernote-0.2.0}/CLAUDE.md +0 -0
- {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/__init__.py +0 -0
- {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/actor_ledger.py +0 -0
- {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/cli/__init__.py +0 -0
- {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/errors.py +0 -0
- {hypernote-0.1.2 → hypernote-0.2.0/src}/hypernote/server/__init__.py +0 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/tests/__init__.py +0 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/tests/conftest.py +0 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/tests/helpers.py +0 -0
- {hypernote-0.1.2 → hypernote-0.2.0}/tests/test_actor_ledger.py +0 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
version:
|
|
7
|
+
description: "Version to release (e.g., 0.1.3)"
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
publish_to_pypi:
|
|
11
|
+
description: "Publish to PyPI"
|
|
12
|
+
required: true
|
|
13
|
+
default: true
|
|
14
|
+
type: boolean
|
|
15
|
+
create_draft:
|
|
16
|
+
description: "Create as draft release"
|
|
17
|
+
required: false
|
|
18
|
+
default: false
|
|
19
|
+
type: boolean
|
|
20
|
+
|
|
21
|
+
permissions:
|
|
22
|
+
contents: write
|
|
23
|
+
|
|
24
|
+
jobs:
|
|
25
|
+
validate-inputs:
|
|
26
|
+
runs-on: ubuntu-latest
|
|
27
|
+
outputs:
|
|
28
|
+
version: ${{ steps.validate.outputs.version }}
|
|
29
|
+
steps:
|
|
30
|
+
- name: Validate version format
|
|
31
|
+
id: validate
|
|
32
|
+
run: |
|
|
33
|
+
VERSION="${{ inputs.version }}"
|
|
34
|
+
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*)?$ ]]; then
|
|
35
|
+
echo "❌ Invalid version format: $VERSION"
|
|
36
|
+
echo "Expected semantic version (e.g., 0.1.3, 0.2.0-alpha.1)"
|
|
37
|
+
exit 1
|
|
38
|
+
fi
|
|
39
|
+
echo "✅ Version format is valid"
|
|
40
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
41
|
+
|
|
42
|
+
release:
|
|
43
|
+
needs: validate-inputs
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
outputs:
|
|
46
|
+
version: ${{ steps.version_update.outputs.version }}
|
|
47
|
+
steps:
|
|
48
|
+
- uses: actions/checkout@v6
|
|
49
|
+
with:
|
|
50
|
+
fetch-depth: 0
|
|
51
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
52
|
+
|
|
53
|
+
- uses: astral-sh/setup-uv@v7
|
|
54
|
+
with:
|
|
55
|
+
enable-cache: true
|
|
56
|
+
|
|
57
|
+
- name: Update version and create commit
|
|
58
|
+
id: version_update
|
|
59
|
+
env:
|
|
60
|
+
VERSION: ${{ needs.validate-inputs.outputs.version }}
|
|
61
|
+
run: |
|
|
62
|
+
sed -i -E "0,/^version = \".*\"/s//version = \"$VERSION\"/" pyproject.toml
|
|
63
|
+
|
|
64
|
+
if ! grep -q "version = \"$VERSION\"" pyproject.toml; then
|
|
65
|
+
echo "❌ Failed to update version in pyproject.toml"
|
|
66
|
+
exit 1
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
echo "✅ Version updated to $VERSION"
|
|
70
|
+
|
|
71
|
+
git config user.name "github-actions[bot]"
|
|
72
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
73
|
+
|
|
74
|
+
if ! git diff --quiet pyproject.toml; then
|
|
75
|
+
uv lock
|
|
76
|
+
git add pyproject.toml uv.lock
|
|
77
|
+
git commit -m "chore: bump version to v$VERSION"
|
|
78
|
+
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
|
79
|
+
git push origin "$CURRENT_BRANCH"
|
|
80
|
+
echo "✅ Version commit pushed"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
84
|
+
|
|
85
|
+
- name: Create and push tag
|
|
86
|
+
env:
|
|
87
|
+
VERSION: ${{ steps.version_update.outputs.version }}
|
|
88
|
+
run: |
|
|
89
|
+
TAG="v$VERSION"
|
|
90
|
+
if git tag -l | grep -q "^$TAG$"; then
|
|
91
|
+
git tag -d "$TAG" || true
|
|
92
|
+
git push origin ":refs/tags/$TAG" || true
|
|
93
|
+
fi
|
|
94
|
+
git tag -a "$TAG" -m "Release $TAG"
|
|
95
|
+
git push origin "$TAG"
|
|
96
|
+
echo "✅ Created and pushed tag $TAG"
|
|
97
|
+
|
|
98
|
+
- name: Build package
|
|
99
|
+
run: |
|
|
100
|
+
rm -rf dist/ build/ *.egg-info/
|
|
101
|
+
uv build
|
|
102
|
+
if [ ! -f dist/*.whl ] || [ ! -f dist/*.tar.gz ]; then
|
|
103
|
+
echo "❌ Build artifacts not found"
|
|
104
|
+
exit 1
|
|
105
|
+
fi
|
|
106
|
+
echo "✅ Package built"
|
|
107
|
+
ls -la dist/
|
|
108
|
+
|
|
109
|
+
- name: Verify package
|
|
110
|
+
run: |
|
|
111
|
+
uv run --isolated --no-project --with dist/*.whl python -c "import hypernote; print('ok')"
|
|
112
|
+
echo "✅ Package verified"
|
|
113
|
+
|
|
114
|
+
- uses: actions/upload-artifact@v6
|
|
115
|
+
with:
|
|
116
|
+
name: dist-${{ steps.version_update.outputs.version }}
|
|
117
|
+
path: dist/*
|
|
118
|
+
if-no-files-found: error
|
|
119
|
+
|
|
120
|
+
- name: Run tests
|
|
121
|
+
run: |
|
|
122
|
+
uv run --extra dev playwright install --with-deps chromium
|
|
123
|
+
uv run --extra dev python -m pytest -q
|
|
124
|
+
|
|
125
|
+
- name: Create GitHub Release
|
|
126
|
+
env:
|
|
127
|
+
GH_TOKEN: ${{ github.token }}
|
|
128
|
+
run: |
|
|
129
|
+
TAG="v${{ steps.version_update.outputs.version }}"
|
|
130
|
+
if gh release view "$TAG" >/dev/null 2>&1; then
|
|
131
|
+
gh release upload "$TAG" dist/* --clobber
|
|
132
|
+
else
|
|
133
|
+
gh release create "$TAG" dist/* \
|
|
134
|
+
--generate-notes \
|
|
135
|
+
--verify-tag \
|
|
136
|
+
${{ inputs.create_draft && '--draft' || '' }}
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
- name: Summary
|
|
140
|
+
run: |
|
|
141
|
+
echo "## Release Summary" >> $GITHUB_STEP_SUMMARY
|
|
142
|
+
echo "- **Version:** v${{ steps.version_update.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
|
143
|
+
echo "- **PyPI:** ${{ inputs.publish_to_pypi }}" >> $GITHUB_STEP_SUMMARY
|
|
144
|
+
echo "- **Draft:** ${{ inputs.create_draft }}" >> $GITHUB_STEP_SUMMARY
|
|
145
|
+
|
|
146
|
+
publish-pypi:
|
|
147
|
+
needs: release
|
|
148
|
+
if: ${{ inputs.publish_to_pypi }}
|
|
149
|
+
runs-on: ubuntu-latest
|
|
150
|
+
steps:
|
|
151
|
+
- uses: actions/download-artifact@v5
|
|
152
|
+
with:
|
|
153
|
+
name: dist-${{ needs.release.outputs.version }}
|
|
154
|
+
path: dist/
|
|
155
|
+
|
|
156
|
+
- uses: astral-sh/setup-uv@v7
|
|
157
|
+
|
|
158
|
+
- name: Publish to PyPI
|
|
159
|
+
env:
|
|
160
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
161
|
+
run: uv publish
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Hypernote
|
|
2
|
+
|
|
3
|
+
Notebook-first execution system built on top of Jupyter shared documents
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv sync --extra dev
|
|
9
|
+
uv run hypernote
|
|
10
|
+
uv run hypernote --help
|
|
11
|
+
uv run hypernote setup serve
|
|
12
|
+
uv run hypernote setup doctor
|
|
13
|
+
uv run hypernote create tmp/demo.ipynb
|
|
14
|
+
uv run hypernote ix tmp/demo.ipynb -s 'value = 20 + 22\nprint(value)'
|
|
15
|
+
uv run hypernote status tmp/demo.ipynb --full
|
|
16
|
+
uv run python -m pytest -q
|
|
17
|
+
uv run ruff check src/hypernote tests
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Architecture
|
|
21
|
+
|
|
22
|
+
Jupyter owns notebook truth:
|
|
23
|
+
|
|
24
|
+
- `.ipynb` persistence
|
|
25
|
+
- shared YDoc document state
|
|
26
|
+
- kernel and session primitives
|
|
27
|
+
- notebook rendering in JupyterLab
|
|
28
|
+
|
|
29
|
+
Hypernote owns a thin control plane:
|
|
30
|
+
|
|
31
|
+
- public SDK in [src/hypernote/sdk.py](src/hypernote/sdk.py)
|
|
32
|
+
- public errors in [src/hypernote/errors.py](src/hypernote/errors.py)
|
|
33
|
+
- agent-first CLI in [src/hypernote/cli/main.py](src/hypernote/cli/main.py)
|
|
34
|
+
- execution orchestration and shared-document mutation in [src/hypernote/execution_orchestrator.py](src/hypernote/execution_orchestrator.py)
|
|
35
|
+
- runtime ownership in [src/hypernote/runtime_manager.py](src/hypernote/runtime_manager.py)
|
|
36
|
+
- HTTP handlers in [src/hypernote/server/handlers.py](src/hypernote/server/handlers.py)
|
|
37
|
+
- Jupyter extension wiring in [src/hypernote/server/extension.py](src/hypernote/server/extension.py)
|
|
38
|
+
- ephemeral job and attribution ledger in [src/hypernote/actor_ledger.py](src/hypernote/actor_ledger.py)
|
|
39
|
+
- subshell-aware execute/interrupt/restart in [src/hypernote/server/subshell.py](src/hypernote/server/subshell.py)
|
|
40
|
+
- optional VS Code embedding surface in [vscode-extension/src/extension.ts](vscode-extension/src/extension.ts)
|
|
41
|
+
|
|
42
|
+
Core rule: notebook edits and execution must operate on one logical document truth whether JupyterLab is closed, already open, or opened mid-run.
|
|
43
|
+
|
|
44
|
+
Lifecycle rule: notebook contents and outputs persist through Jupyter's `.ipynb` model, but Hypernote's runtime state, job records, and cell attribution are intentionally in-memory and notebook-scoped.
|
|
45
|
+
|
|
46
|
+
Concurrent-actor rule: JupyterLab and Hypernote share one notebook session and one kernel. Hypernote-driven cells run in an ipykernel subshell so the kernel's main shell stays responsive to native Lab actions. Hypernote's extension overrides `/api/kernels/{id}/interrupt` and `/api/kernels/{id}/restart` so Lab's Stop and Restart toolbar buttons reach the subshell-routed cell or perform the right cleanup. See [dev/current-architecture.md](dev/current-architecture.md) for the full mechanism.
|
|
47
|
+
|
|
48
|
+
## Shipped Surface
|
|
49
|
+
|
|
50
|
+
### SDK
|
|
51
|
+
|
|
52
|
+
- `hypernote.connect(path, create=False)`
|
|
53
|
+
- `Notebook`, `CellCollection`, `CellHandle`, `Runtime`, `Job`
|
|
54
|
+
- `nb.run(...)`, `nb.run_all()`, `nb.restart()`, `nb.interrupt()`
|
|
55
|
+
- `nb.snapshot()`, `nb.status()`, `nb.diff(...)`
|
|
56
|
+
|
|
57
|
+
### CLI
|
|
58
|
+
|
|
59
|
+
- `hypernote` — live workspace dashboard with hints
|
|
60
|
+
- `create`
|
|
61
|
+
- `ix`
|
|
62
|
+
- `exec`
|
|
63
|
+
- `edit`
|
|
64
|
+
- `run-all`
|
|
65
|
+
- `restart`
|
|
66
|
+
- `restart-run-all`
|
|
67
|
+
- `interrupt`
|
|
68
|
+
- `status`
|
|
69
|
+
- `diff`
|
|
70
|
+
- `cat`
|
|
71
|
+
- `job ...`
|
|
72
|
+
- `runtime ...`
|
|
73
|
+
- `setup doctor`
|
|
74
|
+
- `setup serve`
|
|
75
|
+
|
|
76
|
+
Default CLI contract:
|
|
77
|
+
|
|
78
|
+
- bare `hypernote` shows live workspace state and next-step hints
|
|
79
|
+
- TTY: concise human-readable progress
|
|
80
|
+
- non-TTY: one compact final JSON result
|
|
81
|
+
- explicit streaming only through `--watch` or `--stream-json`
|
|
82
|
+
- summary-first read payloads should come from SDK-backed observation helpers, not CLI-only formatting rules
|
|
83
|
+
- `setup serve` is the default local bootstrap path for a Hypernote-enabled Jupyter server
|
|
84
|
+
- `setup doctor --path PATH` is the preferred first diagnostic when server reachability,
|
|
85
|
+
kernelspec selection, or runtime mismatch is unclear
|
|
86
|
+
|
|
87
|
+
## Rules
|
|
88
|
+
|
|
89
|
+
- Terminology: when the user says "our system", treat that as the maintained project-operating surface, including `AGENTS.md`, `SKILL.md`, `docs/`, `dev/`, tests, and other shared guidance or verification artifacts around the code.
|
|
90
|
+
- SDK first. CLI behavior should come from the SDK, not duplicate raw HTTP semantics.
|
|
91
|
+
- When CLI and SDK both need compact observation behavior, define the summary/truncation/focused-read logic in the SDK and let the CLI adapt it.
|
|
92
|
+
- Shared logic needs one owner. When a helper or shaping rule moves into the SDK or another shared layer, delete the old copies instead of letting multiple versions drift.
|
|
93
|
+
- One truth. Do not reintroduce a contents-vs-YDoc split for notebook reads or writes.
|
|
94
|
+
- Runtime creation must honor the requested kernel first, otherwise notebook metadata
|
|
95
|
+
`kernelspec.name`, otherwise `python3`.
|
|
96
|
+
- Keep control-plane state ephemeral. Do not add durable job history unless the product explicitly needs it.
|
|
97
|
+
- Our system is part of done. After every meaningful change, update the relevant parts of `AGENTS.md`, `SKILL.md`, `docs/`, `dev/`, tests, and adjacent shared project guidance so they stay in sync with implementation.
|
|
98
|
+
- Keep adapters thin. CLI, JupyterLab, and tests should reuse shared contracts instead of re-encoding notebook behavior.
|
|
99
|
+
- Treat output and API shapes as contracts. Feature variants should preserve the same top-level envelope and field semantics unless there is a deliberate, documented exception.
|
|
100
|
+
- Normalize boundary inputs early. If upstream payloads can arrive in more than one valid shape, accept and normalize them at the adapter boundary rather than assuming a single representation.
|
|
101
|
+
- Prefer unique notebook paths in tests and demos. Browser tests must also use unique JupyterLab workspace URLs.
|
|
102
|
+
- Keep `tmp/` disposable. Durable notes belong in `docs/` or `dev/`, not `tmp/`.
|
|
103
|
+
|
|
104
|
+
## Read These First
|
|
105
|
+
|
|
106
|
+
- [SKILL.md](SKILL.md)
|
|
107
|
+
- [docs/README.md](docs/README.md)
|
|
108
|
+
- [dev/README.md](dev/README.md)
|
|
109
|
+
|
|
110
|
+
## If You Are Editing...
|
|
111
|
+
|
|
112
|
+
### `vscode-extension/*`
|
|
113
|
+
|
|
114
|
+
- keep the extension decoupled from Hypernote-specific notebook semantics
|
|
115
|
+
- prefer embedding JupyterLab over recreating notebook behavior in VS Code
|
|
116
|
+
- if the extension launches Jupyter itself, keep that process local, explicit, and easy to inspect
|
|
117
|
+
- update [docs/vscode-extension.md](docs/vscode-extension.md)
|
|
118
|
+
- update [dev/vscode-extension.md](dev/vscode-extension.md)
|
|
119
|
+
|
|
120
|
+
### `src/hypernote/sdk.py` or `src/hypernote/errors.py`
|
|
121
|
+
|
|
122
|
+
- preserve the notebook-first public object model
|
|
123
|
+
- keep public enums and errors stable
|
|
124
|
+
- prefer adding reusable observation helpers on `NotebookStatus` / `CellStatus` over adding CLI-only shaping logic
|
|
125
|
+
- update [docs/sdk.md](docs/sdk.md)
|
|
126
|
+
|
|
127
|
+
### `src/hypernote/cli/main.py`
|
|
128
|
+
|
|
129
|
+
- keep non-TTY output compact by default
|
|
130
|
+
- keep bare `hypernote` as the live dashboard view
|
|
131
|
+
- preserve `ix` as the happy-path command
|
|
132
|
+
- preserve summary-first `status` and compact `cat` with contextual hints
|
|
133
|
+
- prefer rendering SDK observation helpers over introducing new CLI-only data shaping
|
|
134
|
+
- keep streaming explicit in non-TTY mode
|
|
135
|
+
- update [docs/cli.md](docs/cli.md)
|
|
136
|
+
|
|
137
|
+
### `src/hypernote/execution_orchestrator.py`, `src/hypernote/runtime_manager.py`, or `src/hypernote/server/*`
|
|
138
|
+
|
|
139
|
+
- preserve the single-truth shared-document path
|
|
140
|
+
- verify open-tab and late-open behavior still hold
|
|
141
|
+
- update [dev/current-architecture.md](dev/current-architecture.md)
|
|
142
|
+
- if browser-visible behavior changes, update [docs/browser-regression-spec.md](docs/browser-regression-spec.md)
|
|
143
|
+
|
|
144
|
+
### `tests/*`
|
|
145
|
+
|
|
146
|
+
- prefer the narrowest test that proves the behavior
|
|
147
|
+
- preserve coverage for:
|
|
148
|
+
- SDK shape
|
|
149
|
+
- CLI output contract
|
|
150
|
+
- live server behavior
|
|
151
|
+
- browser regression for streaming and late-open correctness
|
|
152
|
+
- for contract-heavy changes, add invariant coverage for:
|
|
153
|
+
- default and focused variants
|
|
154
|
+
- empty and failure states
|
|
155
|
+
- alternate valid input shapes from upstream payloads
|
|
156
|
+
- parity between real helpers and any fake/test-double implementations
|
|
157
|
+
|
|
158
|
+
## Verification
|
|
159
|
+
|
|
160
|
+
Install guidance:
|
|
161
|
+
|
|
162
|
+
- `uv sync`
|
|
163
|
+
- base Hypernote runtime/server usage
|
|
164
|
+
- `uv sync --extra lab`
|
|
165
|
+
- adds the collaborative JupyterLab bundle
|
|
166
|
+
- `uv sync --extra dev`
|
|
167
|
+
- adds local development, lint, test, and browser-validation tooling
|
|
168
|
+
|
|
169
|
+
Minimum checks for most changes:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
uv run ruff check src/hypernote tests
|
|
173
|
+
uv run python -m pytest -q
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
When browser or live-server behavior changes, also use:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
HYPERNOTE_INTEGRATION=1 uv run python -m pytest -q tests/test_live_server.py
|
|
180
|
+
uv run python -m pytest -q tests/test_browser_regression.py
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Before opening or updating a PR for a cross-surface change, do a short contract pass:
|
|
184
|
+
|
|
185
|
+
- check that sibling command variants still share one consistent envelope
|
|
186
|
+
- check that aggregate field names still match their exact semantics
|
|
187
|
+
- check that docs and hints only mention shipped commands and flags
|
|
188
|
+
- check that moved logic no longer has stale copies in adapters or tests
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## Unreleased
|
|
6
|
+
|
|
7
|
+
## 0.2.0 - 2026-05-07
|
|
8
|
+
|
|
9
|
+
Native JupyterLab as a first-class concurrent actor: open a notebook
|
|
10
|
+
mid-run and see streaming output, click Stop and the cell terminates,
|
|
11
|
+
click Restart and the kernel comes back ready. Plus the package now ships
|
|
12
|
+
in PyPA src layout and an experimental VS Code extension.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- subshell-routed kernel execution (JEP 91 / ipykernel 7+): Hypernote sends `execute_request` with a `subshell_id` so the kernel's main shell stays free to answer concurrent clients (e.g. JupyterLab) — opening a notebook mid-run now renders cells immediately and continues to stream output without waiting for the running cell
|
|
17
|
+
- subshell-aware `POST /api/kernels/{id}/interrupt` override: JupyterLab's Stop button (and `nb.interrupt()`) now terminates a Hypernote-driven cell, raising `KeyboardInterrupt` in the subshell thread via a main-shell `PyThreadState_SetAsyncExc` injection. Falls back to default SIGINT for non-Hypernote-driven kernels.
|
|
18
|
+
- subshell- and nbmodel-aware `POST /api/kernels/{id}/restart` override: JupyterLab's Restart button now leaves the kernel ready to run new cells. Hypernote evicts nbmodel's stale per-kernel client and worker, and clears its cached subshell id, so the next execute rebuilds against the fresh kernel.
|
|
19
|
+
- new browser regression tests for Lab Stop and Lab Restart against subshell-routed cells; new real-kernel unit tests for subshell creation, routing, interrupt latency, and restart cleanup.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- package layout migrated to `src/hypernote/` (PyPA src layout). `pyproject.toml` now configures `[tool.hatch.build.targets.wheel] packages = ["src/hypernote"]` and `[tool.ruff] src = ["src", "tests"]`. The `hypernote` import name is unchanged — `import hypernote` continues to work.
|
|
24
|
+
- release workflow switched from tag-triggered to `workflow_dispatch` — run `gh workflow run release.yml -f version=X.Y.Z` to release
|
|
25
|
+
|
|
26
|
+
### Notes
|
|
27
|
+
|
|
28
|
+
- subshell routing requires ipykernel 7+ (IPython kernels). Other kernels fall back to the main shell — late-open during a long-running cell will block the JupyterLab UI for those kernels and the subshell-targeted interrupt becomes a no-op (override falls through to SIGINT, which works on the main shell).
|
|
29
|
+
- `PyThreadState_SetAsyncExc`-based interrupt cannot terminate a thread inside a long blocking C call without GIL release (e.g. `requests.get` with no timeout). The `KeyboardInterrupt` only fires once control returns to Python. The interrupt snippet falls back to `os.kill(pid, SIGINT)` internally if the subshell thread cannot be found, so user-visible "Stop did nothing" cases degrade to default SIGINT behavior rather than silent failure.
|
|
30
|
+
|
|
31
|
+
## 0.1.3 - 2026-04-03
|
|
32
|
+
|
|
33
|
+
Cross-repo runtime hardening and agent ergonomics.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- `hypernote setup serve` — bootstraps a Hypernote-enabled Jupyter server with all required extensions
|
|
38
|
+
- `hypernote setup doctor --path PATH` — reports notebook kernelspec, live runtime kernel, resolved launcher, and warns on mismatches
|
|
39
|
+
- `hypernote create --empty` — removes any default cells Jupyter auto-inserts so notebooks start clean
|
|
40
|
+
- batch `ix` output now includes `cells_inserted`, `cells_total`, `cells_remaining`, `halt_reason`, and `last_processed_cell_id` on early halt
|
|
41
|
+
- timeout errors now surface job id, last known status, and recovery hints pointing to `job get` and `cat`
|
|
42
|
+
- runtime kernel mismatch detection — clear error when a live runtime's kernel doesn't match notebook metadata, with guidance to restart
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- execution now resolves kernels as: explicit override > notebook metadata `kernelspec.name` > `python3`
|
|
47
|
+
- `RuntimeManager.ensure_room()` rejects silent reuse when a live room exists with a different kernel name
|
|
48
|
+
- removed all hardcoded local paths from project markdown files — links are now repo-relative
|
|
49
|
+
- SKILL.md rewritten: iterative `ix → observe → ix` is the primary workflow, heredoc/stdin documented for multi-line cells, server lifecycle section added, cross-repo setup simplified to `uv add hypernote --dev`
|
|
50
|
+
|
|
51
|
+
### Notes
|
|
52
|
+
|
|
53
|
+
- `--cells-file` batch mode is now documented as a convenience for known-good sequences, not the default workflow
|
|
54
|
+
- the recommended cross-repo pattern is now: install hypernote in the target repo, not `uv run --with`
|
|
55
|
+
|
|
56
|
+
## 0.1.1 - 2026-04-02
|
|
57
|
+
|
|
58
|
+
Patch release focused on release automation hardening.
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- updated the GitHub release workflow to newer official action majors where available
|
|
63
|
+
- replaced the third-party GitHub release action with the `gh` CLI in release automation
|
|
64
|
+
- fixed the release workflow to install Playwright browser binaries before running browser tests
|
|
65
|
+
- fixed the release workflow to run tests with the `dev` extra installed
|
|
66
|
+
- fixed the PyPI publish step to use token-only `uv publish` authentication
|
|
67
|
+
|
|
68
|
+
### Notes
|
|
69
|
+
|
|
70
|
+
- package code is unchanged from `0.1.0`
|
|
71
|
+
- this release exists to verify and stabilize the automated release path
|
|
72
|
+
|
|
73
|
+
## 0.1.0 - 2026-04-02
|
|
74
|
+
|
|
75
|
+
Initial public release.
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
|
|
79
|
+
- notebook-first Python SDK built around `Notebook`, `CellCollection`, `CellHandle`, `Runtime`, and `Job`
|
|
80
|
+
- agent-first CLI with `create`, `ix`, `exec`, `edit`, `run-all`, `restart`, `interrupt`, `status`, `diff`, `cat`, `job`, and `runtime` flows
|
|
81
|
+
- Jupyter server extension with narrow Hypernote REST handlers
|
|
82
|
+
- notebook-scoped runtime lifecycle with attach, detach, recovery, stop, and GC
|
|
83
|
+
- headless execution flow over Jupyter shared documents and `jupyter-server-nbmodel`
|
|
84
|
+
- job polling and `input()` round-trip support for long-running or interactive execution
|
|
85
|
+
- live-server and browser regression tests for late-open, persistence, and shared-document correctness
|
|
86
|
+
- project and developer docs for the runtime model, SDK, CLI, and release workflow
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
|
|
90
|
+
- aligned the control plane around an explicitly ephemeral lifecycle
|
|
91
|
+
- moved job tracking and cell attribution to an in-memory notebook-scoped ledger
|
|
92
|
+
- removed the SQLite dependency and any implied durable job history
|
|
93
|
+
|
|
94
|
+
### Notes
|
|
95
|
+
|
|
96
|
+
- Jupyter owns durable notebook contents and outputs in `.ipynb`
|
|
97
|
+
- Hypernote owns ephemeral runtime state, jobs, and attribution
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hypernote
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Thin control plane for Jupyter notebook execution with jobs, attribution, and runtime lifecycle
|
|
5
5
|
Project-URL: Homepage, https://github.com/gilad-rubin/hypernote
|
|
6
6
|
Project-URL: Repository, https://github.com/gilad-rubin/hypernote
|
|
@@ -33,9 +33,10 @@ Description-Content-Type: text/markdown
|
|
|
33
33
|
|
|
34
34
|
## What it ships
|
|
35
35
|
|
|
36
|
-
- notebook-first SDK in `hypernote/sdk.py`
|
|
37
|
-
- agent-first CLI in `hypernote/cli/main.py`
|
|
36
|
+
- notebook-first SDK in `src/hypernote/sdk.py`
|
|
37
|
+
- agent-first CLI in `src/hypernote/cli/main.py`
|
|
38
38
|
- Jupyter server extension for execution and runtime control
|
|
39
|
+
- experimental VS Code extension in `vscode-extension/` for embedding JupyterLab in VS Code
|
|
39
40
|
- notebook-scoped runtime lifecycle with attach, detach, recovery, and stop
|
|
40
41
|
- job polling and `input()` round-trips for headless execution
|
|
41
42
|
- live-server and browser regression coverage for shared-document behavior
|
|
@@ -45,11 +46,16 @@ Description-Content-Type: text/markdown
|
|
|
45
46
|
```bash
|
|
46
47
|
uv sync
|
|
47
48
|
uv run hypernote --help
|
|
49
|
+
uv run hypernote setup serve
|
|
50
|
+
uv run hypernote setup doctor
|
|
48
51
|
uv run hypernote create tmp/demo.ipynb
|
|
49
52
|
uv run hypernote ix tmp/demo.ipynb -s 'value = 20 + 22\nprint(value)'
|
|
50
53
|
uv run hypernote status tmp/demo.ipynb --full
|
|
51
54
|
```
|
|
52
55
|
|
|
56
|
+
For another repo's environment, install Hypernote there (`uv add hypernote --dev`) and run
|
|
57
|
+
the same bootstrap command from that repo.
|
|
58
|
+
|
|
53
59
|
## Install tiers
|
|
54
60
|
|
|
55
61
|
- `hypernote`
|
|
@@ -86,12 +92,29 @@ Hypernote owns:
|
|
|
86
92
|
- actor attribution
|
|
87
93
|
- SDK, CLI, and thin REST handlers
|
|
88
94
|
|
|
95
|
+
## Design discipline
|
|
96
|
+
|
|
97
|
+
- shared behavior should have one owner, usually the SDK for agent-facing observation rules
|
|
98
|
+
- command and payload variants should preserve one contract unless a difference is explicit and documented
|
|
99
|
+
- adapters should normalize valid upstream shape differences at the boundary
|
|
100
|
+
- tests should cover invariants across variants, not only the main workflow
|
|
101
|
+
|
|
89
102
|
## Documentation
|
|
90
103
|
|
|
91
|
-
- [Getting Started](
|
|
92
|
-
- [CLI Reference](
|
|
93
|
-
- [SDK Reference](
|
|
94
|
-
- [Runtime Model](
|
|
104
|
+
- [Getting Started](docs/getting-started.md)
|
|
105
|
+
- [CLI Reference](docs/cli.md)
|
|
106
|
+
- [SDK Reference](docs/sdk.md)
|
|
107
|
+
- [Runtime Model](docs/runtime-model.md)
|
|
108
|
+
- [VS Code Extension](docs/vscode-extension.md)
|
|
109
|
+
|
|
110
|
+
## VS Code
|
|
111
|
+
|
|
112
|
+
The repository now includes a minimal VS Code extension under `vscode-extension/`.
|
|
113
|
+
|
|
114
|
+
- It embeds JupyterLab inside a VS Code custom editor or panel.
|
|
115
|
+
- It can reuse an existing Jupyter server via settings.
|
|
116
|
+
- If no server is reachable, it can start a managed local `jupyter lab` process.
|
|
117
|
+
- It stays decoupled from Hypernote-specific UI so Hypernote can connect to the same server separately.
|
|
95
118
|
|
|
96
119
|
## Verification
|
|
97
120
|
|
|
@@ -102,6 +125,14 @@ uv sync --extra dev
|
|
|
102
125
|
```
|
|
103
126
|
|
|
104
127
|
```bash
|
|
105
|
-
uv run ruff check hypernote tests
|
|
128
|
+
uv run ruff check src/hypernote tests
|
|
106
129
|
uv run python -m pytest -q
|
|
107
130
|
```
|
|
131
|
+
|
|
132
|
+
Extension build:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
cd vscode-extension
|
|
136
|
+
npm install
|
|
137
|
+
npm run compile
|
|
138
|
+
```
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
## What it ships
|
|
9
9
|
|
|
10
|
-
- notebook-first SDK in `hypernote/sdk.py`
|
|
11
|
-
- agent-first CLI in `hypernote/cli/main.py`
|
|
10
|
+
- notebook-first SDK in `src/hypernote/sdk.py`
|
|
11
|
+
- agent-first CLI in `src/hypernote/cli/main.py`
|
|
12
12
|
- Jupyter server extension for execution and runtime control
|
|
13
|
+
- experimental VS Code extension in `vscode-extension/` for embedding JupyterLab in VS Code
|
|
13
14
|
- notebook-scoped runtime lifecycle with attach, detach, recovery, and stop
|
|
14
15
|
- job polling and `input()` round-trips for headless execution
|
|
15
16
|
- live-server and browser regression coverage for shared-document behavior
|
|
@@ -19,11 +20,16 @@
|
|
|
19
20
|
```bash
|
|
20
21
|
uv sync
|
|
21
22
|
uv run hypernote --help
|
|
23
|
+
uv run hypernote setup serve
|
|
24
|
+
uv run hypernote setup doctor
|
|
22
25
|
uv run hypernote create tmp/demo.ipynb
|
|
23
26
|
uv run hypernote ix tmp/demo.ipynb -s 'value = 20 + 22\nprint(value)'
|
|
24
27
|
uv run hypernote status tmp/demo.ipynb --full
|
|
25
28
|
```
|
|
26
29
|
|
|
30
|
+
For another repo's environment, install Hypernote there (`uv add hypernote --dev`) and run
|
|
31
|
+
the same bootstrap command from that repo.
|
|
32
|
+
|
|
27
33
|
## Install tiers
|
|
28
34
|
|
|
29
35
|
- `hypernote`
|
|
@@ -60,12 +66,29 @@ Hypernote owns:
|
|
|
60
66
|
- actor attribution
|
|
61
67
|
- SDK, CLI, and thin REST handlers
|
|
62
68
|
|
|
69
|
+
## Design discipline
|
|
70
|
+
|
|
71
|
+
- shared behavior should have one owner, usually the SDK for agent-facing observation rules
|
|
72
|
+
- command and payload variants should preserve one contract unless a difference is explicit and documented
|
|
73
|
+
- adapters should normalize valid upstream shape differences at the boundary
|
|
74
|
+
- tests should cover invariants across variants, not only the main workflow
|
|
75
|
+
|
|
63
76
|
## Documentation
|
|
64
77
|
|
|
65
|
-
- [Getting Started](
|
|
66
|
-
- [CLI Reference](
|
|
67
|
-
- [SDK Reference](
|
|
68
|
-
- [Runtime Model](
|
|
78
|
+
- [Getting Started](docs/getting-started.md)
|
|
79
|
+
- [CLI Reference](docs/cli.md)
|
|
80
|
+
- [SDK Reference](docs/sdk.md)
|
|
81
|
+
- [Runtime Model](docs/runtime-model.md)
|
|
82
|
+
- [VS Code Extension](docs/vscode-extension.md)
|
|
83
|
+
|
|
84
|
+
## VS Code
|
|
85
|
+
|
|
86
|
+
The repository now includes a minimal VS Code extension under `vscode-extension/`.
|
|
87
|
+
|
|
88
|
+
- It embeds JupyterLab inside a VS Code custom editor or panel.
|
|
89
|
+
- It can reuse an existing Jupyter server via settings.
|
|
90
|
+
- If no server is reachable, it can start a managed local `jupyter lab` process.
|
|
91
|
+
- It stays decoupled from Hypernote-specific UI so Hypernote can connect to the same server separately.
|
|
69
92
|
|
|
70
93
|
## Verification
|
|
71
94
|
|
|
@@ -76,6 +99,14 @@ uv sync --extra dev
|
|
|
76
99
|
```
|
|
77
100
|
|
|
78
101
|
```bash
|
|
79
|
-
uv run ruff check hypernote tests
|
|
102
|
+
uv run ruff check src/hypernote tests
|
|
80
103
|
uv run python -m pytest -q
|
|
81
104
|
```
|
|
105
|
+
|
|
106
|
+
Extension build:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
cd vscode-extension
|
|
110
|
+
npm install
|
|
111
|
+
npm run compile
|
|
112
|
+
```
|