Metadata-Version: 2.5
Name: jupyter-cell-source
Version: 0.1.0
Summary: Expose the live source of a notebook cell (including unsaved edits) as a JupyterLab command result
Project-URL: Homepage, https://github.com/pikakolendo02/jupyter-cell-source
Project-URL: Repository, https://github.com/pikakolendo02/jupyter-cell-source
Author: pikakolendo02
License: MIT
License-File: LICENSE
Keywords: extension,jupyter,jupyterlab,notebook
Classifier: Framework :: Jupyter
Classifier: Framework :: Jupyter :: JupyterLab
Classifier: Framework :: Jupyter :: JupyterLab :: 4
Classifier: Framework :: Jupyter :: JupyterLab :: Extensions
Classifier: Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.8
Requires-Dist: jupyterlab<5,>=4.0.0
Description-Content-Type: text/markdown

# jupyter-cell-source

A tiny JupyterLab 4 extension that exposes the **live** source of a notebook cell,
including unsaved edits, as a JupyterLab command result.

It exists because two things are true at once:

- `jupyterlab-diff` takes `originalSource` from the caller and does **not** compare it
  with the live cell. A stale `originalSource` silently overwrites unsaved edits on
  Accept/Reject.
- JupyterLab's `/api/contents` returns the **saved file**, not the in-memory buffer.

This command gives a caller (for example an agent driving
`jupyterlab-commands-toolkit`) a reliable way to compare the live buffer with disk
before opening a diff.

## Requirements

- JupyterLab 4.x
- `jupyterlab-commands-toolkit` — provides `execute_command` and returns the
  command's result to the caller.

## Command

```
research:get-cell-source
```

Arguments (both optional):

| Argument | Description |
|---|---|
| `cellId` | Id of the target cell. Defaults to the active cell. |
| `notebookPath` | Notebook path relative to the server root. Defaults to the current notebook. |

The visible tab is preferred. If you pass `notebookPath` and the current tab points
elsewhere, the first matching tab is used.

Return value:

```json
{
  "path": "analysis.ipynb",
  "cellId": "4d6ee618-c7c9-42ba-b3e9-3c1ed3783a03",
  "dirty": false,
  "source": "# cell source, exactly as stored in the model\n..."
}
```

On failure: `{"error": "no_notebook" | "no_model" | "cell_not_found", ...}`.

`dirty` is the document-level flag. To decide whether a **specific cell** is safe to
diff, compare its `source` byte-for-byte with the same cell in the saved `.ipynb`.

## Build

```bash
export PATH=/path/to/jupyter/env/bin:$PATH
jlpm install
jlpm build
```

The prebuilt extension is written to:

```
jupyter_cell_source/labextension/
```

## Install from PyPI

```bash
pip install jupyter-cell-source
```

Then restart JupyterLab. If you have a conda-pypi source configured, the same wheel
can be installed through conda.

## Install from a local build

Copy the built extension into the JupyterLab labextensions directory:

```bash
PREFIX=$(python -c "import sys; print(sys.prefix)")
cp -r jupyter_cell_source/labextension \
  "$PREFIX/share/jupyter/labextensions/jupyter-cell-source"
```

For a conda/mamba environment, this installs into the environment prefix. Make sure
`python` and `jupyter` come from the same environment.

Then restart JupyterLab and reload the page. Verify with:

```bash
jupyter labextension list | grep cell-source
```

## Uninstall

```bash
rm -rf "$PREFIX/share/jupyter/labextensions/jupyter-cell-source"
```

Restart JupyterLab.

## Notes

- Keep a single tab per notebook when driving `jupyterlab-diff`: that extension
  resolves `notebookPath` to the first matching widget, and duplicate tabs can make
  it fail silently. This command prefers the visible tab, but the diff extension
  does not.
- The command reads `cell.sharedModel.getSource()`. It does not save the document.

## License

MIT
