nuspace 0.5.2__tar.gz → 0.5.4__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.
- {nuspace-0.5.2 → nuspace-0.5.4}/CHANGELOG.md +27 -3
- nuspace-0.5.4/PKG-INFO +157 -0
- nuspace-0.5.4/README.md +126 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/examples/space.py +3 -3
- {nuspace-0.5.2 → nuspace-0.5.4}/pyproject.toml +15 -28
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/__init__.py +3 -2
- nuspace-0.5.4/src/nuspace/_cli/__init__.py +12 -0
- {nuspace-0.5.2/src/nuspace/host/cli → nuspace-0.5.4/src/nuspace/_cli}/__main__.py +1 -1
- nuspace-0.5.4/src/nuspace/_cli/_meta.py +78 -0
- nuspace-0.5.4/src/nuspace/_cli/commands/__init__.py +1 -0
- nuspace-0.5.4/src/nuspace/_cli/commands/demo.py +93 -0
- nuspace-0.5.4/src/nuspace/_cli/commands/doctor.py +124 -0
- nuspace-0.5.4/src/nuspace/_cli/commands/init.py +43 -0
- nuspace-0.5.4/src/nuspace/_cli/commands/run.py +44 -0
- nuspace-0.5.4/src/nuspace/_cli/commands/telemetry.py +67 -0
- nuspace-0.5.4/src/nuspace/_cli/main.py +58 -0
- nuspace-0.5.4/src/nuspace/_telemetry/__init__.py +38 -0
- nuspace-0.5.4/src/nuspace/_telemetry/config.py +132 -0
- nuspace-0.5.4/src/nuspace/_telemetry/send.py +179 -0
- nuspace-0.5.4/src/nuspace/ext/__init__.py +26 -0
- {nuspace-0.5.2/src/nuspace/host → nuspace-0.5.4/src/nuspace/ext}/registry.py +29 -6
- nuspace-0.5.4/src/nuspace/ext/specs.py +114 -0
- nuspace-0.5.4/src/nuspace/host/__init__.py +16 -0
- nuspace-0.5.4/src/nuspace/host/presets.py +110 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/host/space.py +30 -32
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/__init__.py +3 -9
- nuspace-0.5.4/src/nuspace/ops/extend.py +134 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/__init__.py +1 -4
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/space.py +3 -19
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/device.py +24 -2
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/shell.py +2 -2
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/sidebar/feed.py +1 -1
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/sidebar/ref.py +13 -3
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/viewer/feed.py +10 -4
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/viewer/ref.py +1 -1
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/home.py +5 -5
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/search.py +2 -2
- nuspace-0.5.4/src/nuspace/system/settings.py +43 -0
- nuspace-0.5.4/tests/nuspace/test_cli.py +240 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_home.py +1 -1
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_host.py +42 -52
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_ops_state.py +16 -15
- nuspace-0.5.4/tests/nuspace/test_packaging.py +49 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_search.py +3 -1
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_settings.py +3 -39
- nuspace-0.5.4/tests/nuspace/test_telemetry.py +195 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_web.py +4 -3
- nuspace-0.5.2/.github/workflows/publish-nuspace-ui.yml +0 -119
- nuspace-0.5.2/.github/workflows/publish-nuspace.yml +0 -135
- nuspace-0.5.2/.github/workflows/publish-nuverse.yml +0 -88
- nuspace-0.5.2/PKG-INFO +0 -70
- nuspace-0.5.2/README.md +0 -40
- nuspace-0.5.2/src/nuspace/agent/__init__.py +0 -211
- nuspace-0.5.2/src/nuspace/agent/cc.py +0 -145
- nuspace-0.5.2/src/nuspace/agent/chat.py +0 -921
- nuspace-0.5.2/src/nuspace/agent/conversation.py +0 -302
- nuspace-0.5.2/src/nuspace/agent/cycles.py +0 -573
- nuspace-0.5.2/src/nuspace/agent/llm.py +0 -96
- nuspace-0.5.2/src/nuspace/agent/panel.py +0 -96
- nuspace-0.5.2/src/nuspace/agent/passes.py +0 -172
- nuspace-0.5.2/src/nuspace/agent/prompt/__init__.py +0 -221
- nuspace-0.5.2/src/nuspace/agent/prompt/catalogue.py +0 -135
- nuspace-0.5.2/src/nuspace/agent/prompt/sections.py +0 -84
- nuspace-0.5.2/src/nuspace/agent/prompt/snippets.py +0 -168
- nuspace-0.5.2/src/nuspace/agent/prompt/surface.py +0 -225
- nuspace-0.5.2/src/nuspace/agent/prompt/text/answer.md +0 -17
- nuspace-0.5.2/src/nuspace/agent/prompt/text/crashcourse.md +0 -97
- nuspace-0.5.2/src/nuspace/agent/prompt/text/cycles.md +0 -92
- nuspace-0.5.2/src/nuspace/agent/prompt/text/drawing.md +0 -266
- nuspace-0.5.2/src/nuspace/agent/prompt/text/examples.md +0 -95
- nuspace-0.5.2/src/nuspace/agent/prompt/text/fabrics.md +0 -24
- nuspace-0.5.2/src/nuspace/agent/prompt/text/finish.md +0 -68
- nuspace-0.5.2/src/nuspace/agent/prompt/text/inspect.md +0 -23
- nuspace-0.5.2/src/nuspace/agent/prompt/text/opening.md +0 -6
- nuspace-0.5.2/src/nuspace/agent/prompt/text/protocol.md +0 -122
- nuspace-0.5.2/src/nuspace/agent/prompt/text/role.md +0 -11
- nuspace-0.5.2/src/nuspace/agent/prompt/text/space.md +0 -94
- nuspace-0.5.2/src/nuspace/agent/prompt/text/speaking.md +0 -109
- nuspace-0.5.2/src/nuspace/agent/prompt/text/task.md +0 -25
- nuspace-0.5.2/src/nuspace/agent/prompt/text/thesis.md +0 -131
- nuspace-0.5.2/src/nuspace/agent/session.py +0 -226
- nuspace-0.5.2/src/nuspace/agent/shapes.py +0 -122
- nuspace-0.5.2/src/nuspace/agent/source.py +0 -284
- nuspace-0.5.2/src/nuspace/agent/trace.py +0 -302
- nuspace-0.5.2/src/nuspace/host/__init__.py +0 -21
- nuspace-0.5.2/src/nuspace/host/cli/__init__.py +0 -10
- nuspace-0.5.2/src/nuspace/host/cli/main.py +0 -119
- nuspace-0.5.2/src/nuspace/ops/extend.py +0 -231
- nuspace-0.5.2/src/nuspace/ops/settings.py +0 -29
- nuspace-0.5.2/src/nuspace/system/settings.py +0 -75
- nuspace-0.5.2/tests/nuspace/test_agent.py +0 -1152
- nuspace-0.5.2/tests/nuspace/test_chat.py +0 -578
- nuspace-0.5.2/tests/nuspace/test_packaging.py +0 -163
- nuspace-0.5.2/tests/nuverse/test_cc_chat.py +0 -112
- nuspace-0.5.2/tests/nuverse/test_input_search.py +0 -77
- nuspace-0.5.2/tests/nuverse/test_lazy.py +0 -41
- nuspace-0.5.2/tests/nuverse/test_planes.py +0 -326
- nuspace-0.5.2/tests/nuverse/test_snippets.py +0 -517
- nuspace-0.5.2/tests/nuverse/test_text_search.py +0 -61
- {nuspace-0.5.2 → nuspace-0.5.4}/.gitignore +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/.pre-commit-config.yaml +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/LICENSE.md +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/Makefile +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/pkgs/ts/nuspace-ui/python/nuspace_ui/build +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/cell.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/kernel.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/pin.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/plane.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/read.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/state.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/tree.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/utils.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/cell.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/connection.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/kernel.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/plane.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/reroot.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/state.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/states.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/__init__.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/backends/__init__.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/backends/async_.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/backends/base.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/backends/mp.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/backends/pool.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/__init__.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/__init__.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/env.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/session.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/sidebar/__init__.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/sidebar/interactions.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/utils.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/viewer/__init__.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/viewer/interactions.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/__init__.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/body.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/dispatch.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/envs.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/kernel.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/out.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/reconcile.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/runs.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/space.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/utils.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/__init__.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/bootstrap.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/init.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/nav.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/reactions.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/reload.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/supervisor.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/utils.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/__init__.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/actions.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/kernel.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/kernel_envs.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/made.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/probe.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/search.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/conftest.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_kernel.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_ops_kernel.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_ops_structure.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_reactions.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_services.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_session_pipe.py +0 -0
- {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_shapes.py +0 -0
|
@@ -2,14 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
## Packages shipped from this repo
|
|
4
4
|
|
|
5
|
-
- **nuspace** (the runtime, the `nuspace` command) — 0.5.
|
|
6
|
-
- **nuspace-ui** (the compiled web bundle) — 0.5.
|
|
7
|
-
- **nuverse** (the Planes and snippets a space ships with) — 0.3.1
|
|
5
|
+
- **nuspace** (the runtime, the `nuspace` command) — 0.5.3
|
|
6
|
+
- **nuspace-ui** (the compiled web bundle) — 0.5.3
|
|
8
7
|
|
|
9
8
|
Below is the changelog for **nuspace** - the full commit stream. Newest first.
|
|
10
9
|
The `nuspace-ui` wheel is the same source tree's vite output and is not tracked
|
|
11
10
|
separately here.
|
|
12
11
|
|
|
12
|
+
## Unreleased
|
|
13
|
+
|
|
14
|
+
## 0.5.4 — 2026-10-17
|
|
15
|
+
|
|
16
|
+
- Point the demos extra at nudemos, the renamed home of the demo spaces
|
|
17
|
+
- Add light and dark hero demo GIFs to the README
|
|
18
|
+
- Trim the README header spacing above the navbar
|
|
19
|
+
- Add the square logo to the README header
|
|
20
|
+
|
|
21
|
+
## 0.5.3 — 2026-10-14
|
|
22
|
+
|
|
23
|
+
- Release nuspace 0.5.3, built on nu 0.6.3 and UI kit 0.3.3
|
|
24
|
+
- Search popup folds snippets into groups, ticks a group or everything at once
|
|
25
|
+
- One run command opens a space in a browser, or headless with nothing drawn
|
|
26
|
+
- Try a Nu demo in a throwaway space with one command
|
|
27
|
+
- Make a directory a space without opening it to run
|
|
28
|
+
- Doctor reports versions, missing pieces, extras and installed extensions
|
|
29
|
+
- Empty cell pinned atop the / menu, starting from a program that runs
|
|
30
|
+
- A dismissed cell menu leaves its cell selected, controls shown while open
|
|
31
|
+
- Extensions get their own home; commands map one to one onto host presets
|
|
32
|
+
- nuspace stands alone: no nuverse dependency, extensions come only from install
|
|
33
|
+
- Park the agent and its Claude Code chats in the archive for now
|
|
34
|
+
- Sidebar and panes resize and fold on the kit's split panels
|
|
35
|
+
- nuverse Config sections open again, paired with their body by id
|
|
36
|
+
|
|
13
37
|
## 0.5.2 — 2026-10-12
|
|
14
38
|
|
|
15
39
|
- Release nuspace 0.5.2, built on nu 0.6.2 and UI kit 0.3.2
|
nuspace-0.5.4/PKG-INFO
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: nuspace
|
|
3
|
+
Version: 0.5.4
|
|
4
|
+
Summary: Nu runtime built on Nu. A self-hosted programmable space that runs Nu programs as a tree of planes and cells.
|
|
5
|
+
Project-URL: Repository, https://github.com/nustackdev/nuspace
|
|
6
|
+
Author-email: Gor Arakelyan <gorarkln@gmail.com>
|
|
7
|
+
License-Expression: AGPL-3.0-or-later
|
|
8
|
+
License-File: LICENSE.md
|
|
9
|
+
Keywords: nu,nuspace,nustack,python,runtime,self-hosted,ui
|
|
10
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Requires-Dist: click>=8.0
|
|
19
|
+
Requires-Dist: nucore>=0.6.3
|
|
20
|
+
Requires-Dist: nuspace-ui>=0.5.3
|
|
21
|
+
Requires-Dist: nustd[kv,mp-pool,proxy,ui,valkey]>=0.6.3
|
|
22
|
+
Requires-Dist: rich-click>=1.6
|
|
23
|
+
Requires-Dist: rich>=10.7
|
|
24
|
+
Requires-Dist: typing-extensions>=4.7.0
|
|
25
|
+
Requires-Dist: virtuals-py[redis]>=0.1.10
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: nustd[all]>=0.6.3; extra == 'all'
|
|
28
|
+
Provides-Extra: demos
|
|
29
|
+
Requires-Dist: nudemos; extra == 'demos'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
<div align="center">
|
|
33
|
+
<img width="128" alt="nuspace" src="https://nustack.dev/brand/logo-square-512@2x.png" />
|
|
34
|
+
<h3>
|
|
35
|
+
nuspace - your computational space
|
|
36
|
+
</h3>
|
|
37
|
+
For everything you work with: notes, data, tools, agents. Open-source, self-hosted, your data stays local.
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<br/>
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
<picture>
|
|
44
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nustackdev/nuspace/main/.github/media/hero-dark.gif">
|
|
45
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/nustackdev/nuspace/main/.github/media/hero-light.gif">
|
|
46
|
+
<img alt="nuspace demo" src="https://raw.githubusercontent.com/nustackdev/nuspace/main/.github/media/hero-light.gif" />
|
|
47
|
+
</picture>
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
<br/>
|
|
51
|
+
|
|
52
|
+
<div align="center">
|
|
53
|
+
|
|
54
|
+
[](https://discord.gg/tCa8YE7XVr)
|
|
55
|
+
[](https://twitter.com/nustackdev)
|
|
56
|
+
|
|
57
|
+
[]()
|
|
58
|
+
[](https://pypi.org/project/nuspace/)
|
|
59
|
+
[](https://pypi.org/project/nuspace/)
|
|
60
|
+
[](https://www.gnu.org/licenses/agpl-3.0)
|
|
61
|
+
[](https://pypi.org/project/nuspace/)
|
|
62
|
+
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
<h3 align="center">
|
|
68
|
+
<a href="#ℹ️-about"><b>About</b></a> •
|
|
69
|
+
<a href="#quickstart"><b>Quickstart</b></a> •
|
|
70
|
+
<a href="#community"><b>Community</b></a>
|
|
71
|
+
</h3>
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
# ℹ️ About
|
|
76
|
+
|
|
77
|
+
Build your computational space for everything you work with: notes, data, tools, agents.
|
|
78
|
+
|
|
79
|
+
Elsewhere, a note is a dead document, data is scattered, tools are siloed and an agent's work is lost in chat. In nuspace, they're all connected cells: living programs that hold data, logic and look in one form.
|
|
80
|
+
|
|
81
|
+
- **Cell**: the one building block. A note, a table, a chart, a job, an agent at work.
|
|
82
|
+
- **Living program**: every cell runs. It keeps its state, reacts to the rest of the space and draws itself on screen.
|
|
83
|
+
- **Connected**: change one cell and everything that depends on it follows, live, in every open tab.
|
|
84
|
+
|
|
85
|
+
> **Program anything.** The data, the logic, the look, even the space itself. You and your agents shape it together, on your machine.
|
|
86
|
+
|
|
87
|
+
> Early. Things move fast and the store format is not frozen yet.
|
|
88
|
+
|
|
89
|
+
## What it can do
|
|
90
|
+
|
|
91
|
+
Every cell gets all of it, nothing to wire up.
|
|
92
|
+
|
|
93
|
+
- **Any data.** A note, a table, a song, a billion-entry log, a genome.
|
|
94
|
+
- **Any logic.** Summarize your inbox, dim the lights at sunset, render a video.
|
|
95
|
+
- **Any UI.** A cell draws itself. Text, tables, charts, forms.
|
|
96
|
+
- **It's live.** Change one cell and everything that depends on it follows live. UI too.
|
|
97
|
+
- **Work scales.** The same cell runs in a worker, across processes or on a cluster.
|
|
98
|
+
- **Data scales.** A counter or a billion rows, same cell. Storage shards underneath.
|
|
99
|
+
- **It's made of itself.** The space has the same shape as its cells, so you and your agents can program it too.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
## Quickstart
|
|
103
|
+
|
|
104
|
+
### Install
|
|
105
|
+
|
|
106
|
+
Python 3.10 or newer.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pip install nuspace
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Run
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
nuspace run my.nuspace
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
A browser opens on http://127.0.0.1:8080 and your space is live. Press `/` on a plane to add a cell. `--headless` runs it with nothing drawn.
|
|
119
|
+
|
|
120
|
+
### Try a demo
|
|
121
|
+
|
|
122
|
+
A throwaway space with a full app in it.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pip install "nuspace[demos]"
|
|
126
|
+
nuspace demo movies
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`nuspace demo` lists them all.
|
|
130
|
+
|
|
131
|
+
### Next
|
|
132
|
+
|
|
133
|
+
- `nuspace doctor` checks the install: versions, extras, extensions.
|
|
134
|
+
- Planes and snippets are extensions, found on install through the `nuspace.extensions` entry point. Bring your own and they live in the space like everything else.
|
|
135
|
+
- Your space is a directory on your machine. All state lives in that one folder.
|
|
136
|
+
|
|
137
|
+
## Community
|
|
138
|
+
|
|
139
|
+
### Badge
|
|
140
|
+
|
|
141
|
+
Building on nuspace? Add the badge to your README:
|
|
142
|
+
|
|
143
|
+
[](https://github.com/nustackdev/nuspace)
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
[](https://github.com/nustackdev/nuspace)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Questions
|
|
150
|
+
|
|
151
|
+
1. [Visit the website](https://nustack.dev)
|
|
152
|
+
2. [Open a feature request or report a bug](https://github.com/nustackdev/nuspace/issues)
|
|
153
|
+
3. [Join the Discord](https://discord.gg/tCa8YE7XVr)
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
GNU Affero General Public License v3.0. See [LICENSE.md](LICENSE.md).
|
nuspace-0.5.4/README.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img width="128" alt="nuspace" src="https://nustack.dev/brand/logo-square-512@2x.png" />
|
|
3
|
+
<h3>
|
|
4
|
+
nuspace - your computational space
|
|
5
|
+
</h3>
|
|
6
|
+
For everything you work with: notes, data, tools, agents. Open-source, self-hosted, your data stays local.
|
|
7
|
+
</div>
|
|
8
|
+
|
|
9
|
+
<br/>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<picture>
|
|
13
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nustackdev/nuspace/main/.github/media/hero-dark.gif">
|
|
14
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/nustackdev/nuspace/main/.github/media/hero-light.gif">
|
|
15
|
+
<img alt="nuspace demo" src="https://raw.githubusercontent.com/nustackdev/nuspace/main/.github/media/hero-light.gif" />
|
|
16
|
+
</picture>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<br/>
|
|
20
|
+
|
|
21
|
+
<div align="center">
|
|
22
|
+
|
|
23
|
+
[](https://discord.gg/tCa8YE7XVr)
|
|
24
|
+
[](https://twitter.com/nustackdev)
|
|
25
|
+
|
|
26
|
+
[]()
|
|
27
|
+
[](https://pypi.org/project/nuspace/)
|
|
28
|
+
[](https://pypi.org/project/nuspace/)
|
|
29
|
+
[](https://www.gnu.org/licenses/agpl-3.0)
|
|
30
|
+
[](https://pypi.org/project/nuspace/)
|
|
31
|
+
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
<h3 align="center">
|
|
37
|
+
<a href="#ℹ️-about"><b>About</b></a> •
|
|
38
|
+
<a href="#quickstart"><b>Quickstart</b></a> •
|
|
39
|
+
<a href="#community"><b>Community</b></a>
|
|
40
|
+
</h3>
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
# ℹ️ About
|
|
45
|
+
|
|
46
|
+
Build your computational space for everything you work with: notes, data, tools, agents.
|
|
47
|
+
|
|
48
|
+
Elsewhere, a note is a dead document, data is scattered, tools are siloed and an agent's work is lost in chat. In nuspace, they're all connected cells: living programs that hold data, logic and look in one form.
|
|
49
|
+
|
|
50
|
+
- **Cell**: the one building block. A note, a table, a chart, a job, an agent at work.
|
|
51
|
+
- **Living program**: every cell runs. It keeps its state, reacts to the rest of the space and draws itself on screen.
|
|
52
|
+
- **Connected**: change one cell and everything that depends on it follows, live, in every open tab.
|
|
53
|
+
|
|
54
|
+
> **Program anything.** The data, the logic, the look, even the space itself. You and your agents shape it together, on your machine.
|
|
55
|
+
|
|
56
|
+
> Early. Things move fast and the store format is not frozen yet.
|
|
57
|
+
|
|
58
|
+
## What it can do
|
|
59
|
+
|
|
60
|
+
Every cell gets all of it, nothing to wire up.
|
|
61
|
+
|
|
62
|
+
- **Any data.** A note, a table, a song, a billion-entry log, a genome.
|
|
63
|
+
- **Any logic.** Summarize your inbox, dim the lights at sunset, render a video.
|
|
64
|
+
- **Any UI.** A cell draws itself. Text, tables, charts, forms.
|
|
65
|
+
- **It's live.** Change one cell and everything that depends on it follows live. UI too.
|
|
66
|
+
- **Work scales.** The same cell runs in a worker, across processes or on a cluster.
|
|
67
|
+
- **Data scales.** A counter or a billion rows, same cell. Storage shards underneath.
|
|
68
|
+
- **It's made of itself.** The space has the same shape as its cells, so you and your agents can program it too.
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
## Quickstart
|
|
72
|
+
|
|
73
|
+
### Install
|
|
74
|
+
|
|
75
|
+
Python 3.10 or newer.
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
pip install nuspace
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Run
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
nuspace run my.nuspace
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
A browser opens on http://127.0.0.1:8080 and your space is live. Press `/` on a plane to add a cell. `--headless` runs it with nothing drawn.
|
|
88
|
+
|
|
89
|
+
### Try a demo
|
|
90
|
+
|
|
91
|
+
A throwaway space with a full app in it.
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install "nuspace[demos]"
|
|
95
|
+
nuspace demo movies
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`nuspace demo` lists them all.
|
|
99
|
+
|
|
100
|
+
### Next
|
|
101
|
+
|
|
102
|
+
- `nuspace doctor` checks the install: versions, extras, extensions.
|
|
103
|
+
- Planes and snippets are extensions, found on install through the `nuspace.extensions` entry point. Bring your own and they live in the space like everything else.
|
|
104
|
+
- Your space is a directory on your machine. All state lives in that one folder.
|
|
105
|
+
|
|
106
|
+
## Community
|
|
107
|
+
|
|
108
|
+
### Badge
|
|
109
|
+
|
|
110
|
+
Building on nuspace? Add the badge to your README:
|
|
111
|
+
|
|
112
|
+
[](https://github.com/nustackdev/nuspace)
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
[](https://github.com/nustackdev/nuspace)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Questions
|
|
119
|
+
|
|
120
|
+
1. [Visit the website](https://nustack.dev)
|
|
121
|
+
2. [Open a feature request or report a bug](https://github.com/nustackdev/nuspace/issues)
|
|
122
|
+
3. [Join the Discord](https://discord.gg/tCa8YE7XVr)
|
|
123
|
+
|
|
124
|
+
## License
|
|
125
|
+
|
|
126
|
+
GNU Affero General Public License v3.0. See [LICENSE.md](LICENSE.md).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
"""A space in the browser, with
|
|
1
|
+
"""A space in the browser, with whatever extensions are installed.
|
|
2
2
|
|
|
3
|
-
Every Plane and snippet comes from
|
|
4
|
-
space is the directory ``examples/example.nuspace``, kept between runs.
|
|
3
|
+
Every Plane and snippet comes from an extension, found through its entry point.
|
|
4
|
+
The space is the directory ``examples/example.nuspace``, kept between runs.
|
|
5
5
|
|
|
6
6
|
Run it::
|
|
7
7
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nuspace"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.4"
|
|
8
8
|
description = "Nu runtime built on Nu. A self-hosted programmable space that runs Nu programs as a tree of planes and cells."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "AGPL-3.0-or-later"
|
|
@@ -14,19 +14,14 @@ dependencies = [
|
|
|
14
14
|
# The fabrics a space runs on, nothing more: kv for the store, valkey for
|
|
15
15
|
# its change notifications, ui for the browser, mp_pool for the workers,
|
|
16
16
|
# proxy (invisibles) for the worker's session.
|
|
17
|
-
"nucore>=0.6.
|
|
18
|
-
"nustd[kv,ui,valkey,mp_pool,proxy]>=0.6.
|
|
17
|
+
"nucore>=0.6.3",
|
|
18
|
+
"nustd[kv,ui,valkey,mp_pool,proxy]>=0.6.3",
|
|
19
19
|
# The store's change notifications run over virtuals' redis backend.
|
|
20
20
|
"virtuals-py[redis]>=0.1.10",
|
|
21
21
|
# The compiled web bundle. A separate distribution only because PyPI caps
|
|
22
22
|
# project size and a SPA rebuilt on every UI tweak would eat the quota --
|
|
23
23
|
# not optional. `pip install nuspace` gives you the browser.
|
|
24
|
-
"nuspace-ui>=0.5.
|
|
25
|
-
# The extensions a space offers out of the box: Planes, snippets. Always
|
|
26
|
-
# pulled, split into extras when its deps grow. nuspace never imports it:
|
|
27
|
-
# it is found through the `nuspace.extensions` entry point, like any
|
|
28
|
-
# third party.
|
|
29
|
-
"nuverse>=0.3.1",
|
|
24
|
+
"nuspace-ui>=0.5.3",
|
|
30
25
|
"typing-extensions>=4.7.0",
|
|
31
26
|
"click>=8.0",
|
|
32
27
|
"rich>=10.7",
|
|
@@ -39,7 +34,6 @@ keywords = [
|
|
|
39
34
|
"runtime",
|
|
40
35
|
"self-hosted",
|
|
41
36
|
"python",
|
|
42
|
-
"ai-agents",
|
|
43
37
|
"ui",
|
|
44
38
|
]
|
|
45
39
|
classifiers = [
|
|
@@ -55,40 +49,35 @@ classifiers = [
|
|
|
55
49
|
[project.optional-dependencies]
|
|
56
50
|
# Every nustd fabric and kv backend, for cells that reach past the defaults.
|
|
57
51
|
all = [
|
|
58
|
-
"nustd[all]>=0.6.
|
|
52
|
+
"nustd[all]>=0.6.3",
|
|
53
|
+
]
|
|
54
|
+
# The Nu demos as Planes, for `nuspace demo` and the `+` picker.
|
|
55
|
+
demos = [
|
|
56
|
+
"nudemos",
|
|
59
57
|
]
|
|
60
58
|
|
|
61
59
|
[project.urls]
|
|
62
60
|
Repository = "https://github.com/nustackdev/nuspace"
|
|
63
61
|
|
|
64
62
|
[project.scripts]
|
|
65
|
-
nuspace = "nuspace.
|
|
63
|
+
nuspace = "nuspace._cli:main"
|
|
66
64
|
|
|
67
65
|
[tool.hatch.build.targets.wheel]
|
|
68
|
-
# Whole directories, not python files: the agent's system prompt is prose in
|
|
69
|
-
# `nuspace/agent/prompt/text/*.md`, read at runtime through
|
|
70
|
-
# importlib.resources. hatchling ships every file under a listed package, so
|
|
71
|
-
# this needs no data entry of its own -- but adding an `include` or
|
|
72
|
-
# `only-include` here would drop the prose and leave a wheel whose chats
|
|
73
|
-
# raise on their first message. Don't.
|
|
74
66
|
packages = ["src/nuspace"]
|
|
75
67
|
|
|
76
68
|
[tool.hatch.build.targets.sdist]
|
|
77
|
-
# pkgs/ holds the sibling
|
|
78
|
-
#
|
|
69
|
+
# pkgs/ holds the sibling nuspace-ui distribution, shipped from its own
|
|
70
|
+
# directory on its own tag.
|
|
79
71
|
exclude = [
|
|
80
72
|
"pkgs",
|
|
73
|
+
".github",
|
|
81
74
|
]
|
|
82
75
|
|
|
83
|
-
[tool.uv.workspace]
|
|
84
|
-
members = ["pkgs/nuverse"]
|
|
85
|
-
|
|
86
76
|
[tool.uv.sources]
|
|
87
|
-
nuverse = { workspace = true }
|
|
88
77
|
nuspace-ui = { path = "./pkgs/ts/nuspace-ui", editable = true }
|
|
89
78
|
nucore = { path = "../nu", editable = true }
|
|
90
79
|
nustd = { path = "../nu/pkgs/nustd", editable = true }
|
|
91
|
-
|
|
80
|
+
nudemos = { path = "../nuverse/pkgs/nudemos", editable = true }
|
|
92
81
|
|
|
93
82
|
[tool.uv]
|
|
94
83
|
default-groups = ["dev"]
|
|
@@ -153,7 +142,6 @@ line-length = 100
|
|
|
153
142
|
target-version = "py310"
|
|
154
143
|
src = [
|
|
155
144
|
"src",
|
|
156
|
-
"pkgs/nuverse/src",
|
|
157
145
|
]
|
|
158
146
|
extend-exclude = [".venv", "build", "dist", "*.egg-info"]
|
|
159
147
|
|
|
@@ -196,10 +184,9 @@ convention = "google"
|
|
|
196
184
|
[tool.ruff.lint.isort]
|
|
197
185
|
known-first-party = [
|
|
198
186
|
"nuspace",
|
|
199
|
-
"nuverse",
|
|
200
187
|
"nu",
|
|
201
188
|
"nustd",
|
|
202
|
-
"
|
|
189
|
+
"nudemos",
|
|
203
190
|
]
|
|
204
191
|
force-single-line = false
|
|
205
192
|
lines-after-imports = 2
|
|
@@ -15,8 +15,9 @@ Workers import this package: nothing here may pull in a server.
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
from nuspace import ops, shapes
|
|
18
|
-
from nuspace.
|
|
19
|
-
from nuspace.
|
|
18
|
+
from nuspace.ext import TEXT, Extension, Plane, Snippet
|
|
19
|
+
from nuspace.host import open_space
|
|
20
|
+
from nuspace.ops import env
|
|
20
21
|
from nuspace.shapes import CellState, PlaneState, Space, States
|
|
21
22
|
from nuspace.system.services import (
|
|
22
23
|
boot,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""The ``nuspace`` command: run a space, try a demo, make one, check the install.
|
|
2
|
+
|
|
3
|
+
Pure command line, not an API: nothing imports it, workers least of all.
|
|
4
|
+
|
|
5
|
+
A space is a directory one process locks at a time, so a command that opens
|
|
6
|
+
one holds it for as long as it is up.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .main import cli, main
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = ["cli", "main"]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""What the commands share: the console, the versions, and how a space is held open."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Callable
|
|
6
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
7
|
+
from typing import Any, TypeVar
|
|
8
|
+
|
|
9
|
+
import rich_click as click
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.text import Text
|
|
12
|
+
|
|
13
|
+
import nu
|
|
14
|
+
from nu._branding import PURPLE
|
|
15
|
+
from nuspace import _telemetry
|
|
16
|
+
from nuspace.system.kernel import NotASpace
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"STORE_ENV",
|
|
21
|
+
"announce",
|
|
22
|
+
"console",
|
|
23
|
+
"hold",
|
|
24
|
+
"opened",
|
|
25
|
+
"path_argument",
|
|
26
|
+
"version_of",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
#: The environment variable naming the space directory when no path is given.
|
|
31
|
+
STORE_ENV = "NUSPACE_STORE"
|
|
32
|
+
|
|
33
|
+
console = Console()
|
|
34
|
+
|
|
35
|
+
_F = TypeVar("_F", bound=Callable[..., Any])
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def version_of(package: str) -> str:
|
|
39
|
+
"""The installed version of ``package``, or a dev marker when it is not installed."""
|
|
40
|
+
try:
|
|
41
|
+
return version(package)
|
|
42
|
+
except PackageNotFoundError:
|
|
43
|
+
return "0.0.0+dev"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def path_argument(fn: _F) -> _F:
|
|
47
|
+
"""The space directory a command takes, from :data:`STORE_ENV` when absent."""
|
|
48
|
+
return click.argument("path", required=False, envvar=STORE_ENV)(fn)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def announce(path: str | None, how: str) -> None:
|
|
52
|
+
"""Say which space this is and how it is open."""
|
|
53
|
+
where = path or "Throwaway space, gone at close"
|
|
54
|
+
console.print(Text.assemble(("nuspace", f"bold {PURPLE}"), (" ", ""), (where, "dim")))
|
|
55
|
+
console.print(f"[dim]{how}, Ctrl+C to stop[/dim]")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def opened(preset: Callable[..., nu.Nu], *args: object, **kwargs: object) -> nu.Nu:
|
|
59
|
+
"""What ``preset`` opens, or a short error when the path is not a space."""
|
|
60
|
+
try:
|
|
61
|
+
return preset(*args, **kwargs)
|
|
62
|
+
except NotASpace as e:
|
|
63
|
+
raise click.ClickException(str(e)) from None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def hold(term: nu.Nu) -> None:
|
|
67
|
+
"""Run a space until interrupted, then let the brackets reap the fleet.
|
|
68
|
+
|
|
69
|
+
The user's first run event goes out here (see :mod:`nuspace._telemetry`):
|
|
70
|
+
on opening a space, never on import. Compiled and evaluated without law
|
|
71
|
+
validation: the space program is ours and tested, and validating its
|
|
72
|
+
whole tree costs seconds per start.
|
|
73
|
+
"""
|
|
74
|
+
_telemetry.first_run()
|
|
75
|
+
try:
|
|
76
|
+
nu.eval_in_loop(nu.compile(term), nu.Context())
|
|
77
|
+
except KeyboardInterrupt:
|
|
78
|
+
console.print("[dim]Stopped[/dim]")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""The commands of the ``nuspace`` group, one module each."""
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""``nuspace demo``: list the demos, or open one in a space.
|
|
2
|
+
|
|
3
|
+
The demos are the Planes ``nudemos`` registers, an optional extra
|
|
4
|
+
(``nuspace[demos]``). Installed, it registers them for ``+`` in every space
|
|
5
|
+
too; this command opens one straight away through the
|
|
6
|
+
:func:`~nuspace.host.demo` preset. The space is a throwaway one unless PATH
|
|
7
|
+
is given, and not ``$NUSPACE_STORE``: a demo never lands in your space
|
|
8
|
+
unless you name it.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
from typing import TYPE_CHECKING
|
|
15
|
+
|
|
16
|
+
import rich_click as click
|
|
17
|
+
from rich.table import Table
|
|
18
|
+
from rich.text import Text
|
|
19
|
+
|
|
20
|
+
from nu._branding import BLUE, PURPLE
|
|
21
|
+
from nuspace.host import presets
|
|
22
|
+
|
|
23
|
+
from .._meta import announce, console, hold, opened
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from nuspace.ext import Plane
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
__all__ = ["INSTALL_HINT", "demo", "demos"]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
#: What to run when the demos are not installed.
|
|
34
|
+
INSTALL_HINT = 'pip install "nuspace[demos]"'
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def demos() -> dict[str, Plane] | None:
|
|
38
|
+
"""The demo Planes by name, in the order registered. None when the extra is missing."""
|
|
39
|
+
try:
|
|
40
|
+
from nudemos import extension
|
|
41
|
+
except ImportError:
|
|
42
|
+
return None
|
|
43
|
+
return {spec.name: spec for spec in extension().planes}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _missing() -> None:
|
|
47
|
+
console.print("[yellow]The demos are not installed.[/yellow]")
|
|
48
|
+
console.print(Text.assemble(("install with: ", "dim"), (INSTALL_HINT, f"bold {BLUE}")))
|
|
49
|
+
sys.exit(1)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _list(found: dict[str, Plane]) -> None:
|
|
53
|
+
table = Table(show_header=False, box=None, padding=(0, 2))
|
|
54
|
+
table.add_column(style=f"bold {BLUE}")
|
|
55
|
+
table.add_column(style="dim")
|
|
56
|
+
for name, spec in found.items():
|
|
57
|
+
table.add_row(name, spec.description)
|
|
58
|
+
console.print(Text("demos", style=f"bold {PURPLE}"))
|
|
59
|
+
console.print(table)
|
|
60
|
+
console.print(
|
|
61
|
+
Text.assemble(("open one with: ", "dim"), ("nuspace demo <name>", f"bold {BLUE}"))
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@click.command(
|
|
66
|
+
short_help="List the demos, or open one in a space.",
|
|
67
|
+
help=(
|
|
68
|
+
"List the demos, or open the one named NAME in a space: a throwaway one,"
|
|
69
|
+
f" or PATH. Needs the demos extra: {INSTALL_HINT}"
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
@click.argument("name", required=False)
|
|
73
|
+
@click.argument("path", required=False)
|
|
74
|
+
@click.option("--host", default="127.0.0.1", show_default=True, help="Interface to bind.")
|
|
75
|
+
@click.option("-p", "--port", default=8080, show_default=True, help="Port to bind.")
|
|
76
|
+
@click.option("--no-browser", is_flag=True, help="Do not open a browser tab on the way up.")
|
|
77
|
+
def demo(name: str | None, path: str | None, host: str, port: int, no_browser: bool) -> None:
|
|
78
|
+
"""No name: list. A name: serve that demo until Ctrl+C."""
|
|
79
|
+
found = demos()
|
|
80
|
+
if found is None:
|
|
81
|
+
_missing()
|
|
82
|
+
return
|
|
83
|
+
if name is None:
|
|
84
|
+
_list(found)
|
|
85
|
+
return
|
|
86
|
+
if name not in found:
|
|
87
|
+
console.print(f"[red]Unknown demo:[/red] [bold]{name}[/bold]", highlight=False)
|
|
88
|
+
console.print(Text.assemble(("available: ", "dim"), (", ".join(found) or "(none)", BLUE)))
|
|
89
|
+
sys.exit(2)
|
|
90
|
+
spec = found[name]
|
|
91
|
+
term = opened(presets.demo, spec, path, host=host, port=port, open_browser=not no_browser)
|
|
92
|
+
announce(path, f"http://{host}:{port}/{presets.demo_id(spec)}")
|
|
93
|
+
hold(term)
|