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.
Files changed (167) hide show
  1. {nuspace-0.5.2 → nuspace-0.5.4}/CHANGELOG.md +27 -3
  2. nuspace-0.5.4/PKG-INFO +157 -0
  3. nuspace-0.5.4/README.md +126 -0
  4. {nuspace-0.5.2 → nuspace-0.5.4}/examples/space.py +3 -3
  5. {nuspace-0.5.2 → nuspace-0.5.4}/pyproject.toml +15 -28
  6. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/__init__.py +3 -2
  7. nuspace-0.5.4/src/nuspace/_cli/__init__.py +12 -0
  8. {nuspace-0.5.2/src/nuspace/host/cli → nuspace-0.5.4/src/nuspace/_cli}/__main__.py +1 -1
  9. nuspace-0.5.4/src/nuspace/_cli/_meta.py +78 -0
  10. nuspace-0.5.4/src/nuspace/_cli/commands/__init__.py +1 -0
  11. nuspace-0.5.4/src/nuspace/_cli/commands/demo.py +93 -0
  12. nuspace-0.5.4/src/nuspace/_cli/commands/doctor.py +124 -0
  13. nuspace-0.5.4/src/nuspace/_cli/commands/init.py +43 -0
  14. nuspace-0.5.4/src/nuspace/_cli/commands/run.py +44 -0
  15. nuspace-0.5.4/src/nuspace/_cli/commands/telemetry.py +67 -0
  16. nuspace-0.5.4/src/nuspace/_cli/main.py +58 -0
  17. nuspace-0.5.4/src/nuspace/_telemetry/__init__.py +38 -0
  18. nuspace-0.5.4/src/nuspace/_telemetry/config.py +132 -0
  19. nuspace-0.5.4/src/nuspace/_telemetry/send.py +179 -0
  20. nuspace-0.5.4/src/nuspace/ext/__init__.py +26 -0
  21. {nuspace-0.5.2/src/nuspace/host → nuspace-0.5.4/src/nuspace/ext}/registry.py +29 -6
  22. nuspace-0.5.4/src/nuspace/ext/specs.py +114 -0
  23. nuspace-0.5.4/src/nuspace/host/__init__.py +16 -0
  24. nuspace-0.5.4/src/nuspace/host/presets.py +110 -0
  25. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/host/space.py +30 -32
  26. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/__init__.py +3 -9
  27. nuspace-0.5.4/src/nuspace/ops/extend.py +134 -0
  28. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/__init__.py +1 -4
  29. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/space.py +3 -19
  30. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/device.py +24 -2
  31. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/shell.py +2 -2
  32. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/sidebar/feed.py +1 -1
  33. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/sidebar/ref.py +13 -3
  34. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/viewer/feed.py +10 -4
  35. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/viewer/ref.py +1 -1
  36. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/home.py +5 -5
  37. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/search.py +2 -2
  38. nuspace-0.5.4/src/nuspace/system/settings.py +43 -0
  39. nuspace-0.5.4/tests/nuspace/test_cli.py +240 -0
  40. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_home.py +1 -1
  41. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_host.py +42 -52
  42. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_ops_state.py +16 -15
  43. nuspace-0.5.4/tests/nuspace/test_packaging.py +49 -0
  44. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_search.py +3 -1
  45. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_settings.py +3 -39
  46. nuspace-0.5.4/tests/nuspace/test_telemetry.py +195 -0
  47. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_web.py +4 -3
  48. nuspace-0.5.2/.github/workflows/publish-nuspace-ui.yml +0 -119
  49. nuspace-0.5.2/.github/workflows/publish-nuspace.yml +0 -135
  50. nuspace-0.5.2/.github/workflows/publish-nuverse.yml +0 -88
  51. nuspace-0.5.2/PKG-INFO +0 -70
  52. nuspace-0.5.2/README.md +0 -40
  53. nuspace-0.5.2/src/nuspace/agent/__init__.py +0 -211
  54. nuspace-0.5.2/src/nuspace/agent/cc.py +0 -145
  55. nuspace-0.5.2/src/nuspace/agent/chat.py +0 -921
  56. nuspace-0.5.2/src/nuspace/agent/conversation.py +0 -302
  57. nuspace-0.5.2/src/nuspace/agent/cycles.py +0 -573
  58. nuspace-0.5.2/src/nuspace/agent/llm.py +0 -96
  59. nuspace-0.5.2/src/nuspace/agent/panel.py +0 -96
  60. nuspace-0.5.2/src/nuspace/agent/passes.py +0 -172
  61. nuspace-0.5.2/src/nuspace/agent/prompt/__init__.py +0 -221
  62. nuspace-0.5.2/src/nuspace/agent/prompt/catalogue.py +0 -135
  63. nuspace-0.5.2/src/nuspace/agent/prompt/sections.py +0 -84
  64. nuspace-0.5.2/src/nuspace/agent/prompt/snippets.py +0 -168
  65. nuspace-0.5.2/src/nuspace/agent/prompt/surface.py +0 -225
  66. nuspace-0.5.2/src/nuspace/agent/prompt/text/answer.md +0 -17
  67. nuspace-0.5.2/src/nuspace/agent/prompt/text/crashcourse.md +0 -97
  68. nuspace-0.5.2/src/nuspace/agent/prompt/text/cycles.md +0 -92
  69. nuspace-0.5.2/src/nuspace/agent/prompt/text/drawing.md +0 -266
  70. nuspace-0.5.2/src/nuspace/agent/prompt/text/examples.md +0 -95
  71. nuspace-0.5.2/src/nuspace/agent/prompt/text/fabrics.md +0 -24
  72. nuspace-0.5.2/src/nuspace/agent/prompt/text/finish.md +0 -68
  73. nuspace-0.5.2/src/nuspace/agent/prompt/text/inspect.md +0 -23
  74. nuspace-0.5.2/src/nuspace/agent/prompt/text/opening.md +0 -6
  75. nuspace-0.5.2/src/nuspace/agent/prompt/text/protocol.md +0 -122
  76. nuspace-0.5.2/src/nuspace/agent/prompt/text/role.md +0 -11
  77. nuspace-0.5.2/src/nuspace/agent/prompt/text/space.md +0 -94
  78. nuspace-0.5.2/src/nuspace/agent/prompt/text/speaking.md +0 -109
  79. nuspace-0.5.2/src/nuspace/agent/prompt/text/task.md +0 -25
  80. nuspace-0.5.2/src/nuspace/agent/prompt/text/thesis.md +0 -131
  81. nuspace-0.5.2/src/nuspace/agent/session.py +0 -226
  82. nuspace-0.5.2/src/nuspace/agent/shapes.py +0 -122
  83. nuspace-0.5.2/src/nuspace/agent/source.py +0 -284
  84. nuspace-0.5.2/src/nuspace/agent/trace.py +0 -302
  85. nuspace-0.5.2/src/nuspace/host/__init__.py +0 -21
  86. nuspace-0.5.2/src/nuspace/host/cli/__init__.py +0 -10
  87. nuspace-0.5.2/src/nuspace/host/cli/main.py +0 -119
  88. nuspace-0.5.2/src/nuspace/ops/extend.py +0 -231
  89. nuspace-0.5.2/src/nuspace/ops/settings.py +0 -29
  90. nuspace-0.5.2/src/nuspace/system/settings.py +0 -75
  91. nuspace-0.5.2/tests/nuspace/test_agent.py +0 -1152
  92. nuspace-0.5.2/tests/nuspace/test_chat.py +0 -578
  93. nuspace-0.5.2/tests/nuspace/test_packaging.py +0 -163
  94. nuspace-0.5.2/tests/nuverse/test_cc_chat.py +0 -112
  95. nuspace-0.5.2/tests/nuverse/test_input_search.py +0 -77
  96. nuspace-0.5.2/tests/nuverse/test_lazy.py +0 -41
  97. nuspace-0.5.2/tests/nuverse/test_planes.py +0 -326
  98. nuspace-0.5.2/tests/nuverse/test_snippets.py +0 -517
  99. nuspace-0.5.2/tests/nuverse/test_text_search.py +0 -61
  100. {nuspace-0.5.2 → nuspace-0.5.4}/.gitignore +0 -0
  101. {nuspace-0.5.2 → nuspace-0.5.4}/.pre-commit-config.yaml +0 -0
  102. {nuspace-0.5.2 → nuspace-0.5.4}/LICENSE.md +0 -0
  103. {nuspace-0.5.2 → nuspace-0.5.4}/Makefile +0 -0
  104. {nuspace-0.5.2 → nuspace-0.5.4}/pkgs/ts/nuspace-ui/python/nuspace_ui/build +0 -0
  105. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/cell.py +0 -0
  106. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/kernel.py +0 -0
  107. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/pin.py +0 -0
  108. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/plane.py +0 -0
  109. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/read.py +0 -0
  110. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/state.py +0 -0
  111. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/tree.py +0 -0
  112. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/ops/utils.py +0 -0
  113. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/cell.py +0 -0
  114. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/connection.py +0 -0
  115. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/kernel.py +0 -0
  116. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/plane.py +0 -0
  117. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/reroot.py +0 -0
  118. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/state.py +0 -0
  119. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/shapes/states.py +0 -0
  120. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/__init__.py +0 -0
  121. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/backends/__init__.py +0 -0
  122. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/backends/async_.py +0 -0
  123. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/backends/base.py +0 -0
  124. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/backends/mp.py +0 -0
  125. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/backends/pool.py +0 -0
  126. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/__init__.py +0 -0
  127. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/__init__.py +0 -0
  128. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/env.py +0 -0
  129. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/session.py +0 -0
  130. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/sidebar/__init__.py +0 -0
  131. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/sidebar/interactions.py +0 -0
  132. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/utils.py +0 -0
  133. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/viewer/__init__.py +0 -0
  134. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/devices/web/viewer/interactions.py +0 -0
  135. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/__init__.py +0 -0
  136. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/body.py +0 -0
  137. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/dispatch.py +0 -0
  138. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/envs.py +0 -0
  139. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/kernel.py +0 -0
  140. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/out.py +0 -0
  141. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/reconcile.py +0 -0
  142. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/runs.py +0 -0
  143. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/space.py +0 -0
  144. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/kernel/utils.py +0 -0
  145. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/__init__.py +0 -0
  146. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/bootstrap.py +0 -0
  147. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/init.py +0 -0
  148. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/nav.py +0 -0
  149. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/reactions.py +0 -0
  150. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/reload.py +0 -0
  151. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/services/supervisor.py +0 -0
  152. {nuspace-0.5.2 → nuspace-0.5.4}/src/nuspace/system/utils.py +0 -0
  153. {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/__init__.py +0 -0
  154. {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/actions.py +0 -0
  155. {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/kernel.py +0 -0
  156. {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/kernel_envs.py +0 -0
  157. {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/made.py +0 -0
  158. {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/probe.py +0 -0
  159. {nuspace-0.5.2 → nuspace-0.5.4}/tests/_lib/_support/search.py +0 -0
  160. {nuspace-0.5.2 → nuspace-0.5.4}/tests/conftest.py +0 -0
  161. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_kernel.py +0 -0
  162. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_ops_kernel.py +0 -0
  163. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_ops_structure.py +0 -0
  164. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_reactions.py +0 -0
  165. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_services.py +0 -0
  166. {nuspace-0.5.2 → nuspace-0.5.4}/tests/nuspace/test_session_pipe.py +0 -0
  167. {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.2
6
- - **nuspace-ui** (the compiled web bundle) — 0.5.2
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
+ [![Discord](https://img.shields.io/badge/discord-join-5865F2?logo=discord&logoColor=white)](https://discord.gg/tCa8YE7XVr)
55
+ [![Twitter Follow](https://img.shields.io/twitter/follow/nustackdev?style=social)](https://twitter.com/nustackdev)
56
+
57
+ [![Platform Support](https://img.shields.io/badge/platform-Linux%20%7C%20macOS-blue)]()
58
+ [![PyPI - Python Version](https://img.shields.io/badge/python-%3E%3D%203.10-blue)](https://pypi.org/project/nuspace/)
59
+ [![PyPI Package](https://img.shields.io/pypi/v/nuspace?color=yellow)](https://pypi.org/project/nuspace/)
60
+ [![License](https://img.shields.io/badge/License-AGPL%20v3-orange.svg)](https://www.gnu.org/licenses/agpl-3.0)
61
+ [![PyPI Downloads](https://img.shields.io/pypi/dw/nuspace?color=green)](https://pypi.org/project/nuspace/)
62
+
63
+ </div>
64
+
65
+ ---
66
+
67
+ <h3 align="center">
68
+ <a href="#ℹ️-about"><b>About</b></a> &bull;
69
+ <a href="#quickstart"><b>Quickstart</b></a> &bull;
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
+ [![nuspace](https://img.shields.io/badge/built%20with-nuspace-%237A4CE0)](https://github.com/nustackdev/nuspace)
144
+
145
+ ```
146
+ [![nuspace](https://img.shields.io/badge/built%20with-nuspace-%237A4CE0)](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).
@@ -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
+ [![Discord](https://img.shields.io/badge/discord-join-5865F2?logo=discord&logoColor=white)](https://discord.gg/tCa8YE7XVr)
24
+ [![Twitter Follow](https://img.shields.io/twitter/follow/nustackdev?style=social)](https://twitter.com/nustackdev)
25
+
26
+ [![Platform Support](https://img.shields.io/badge/platform-Linux%20%7C%20macOS-blue)]()
27
+ [![PyPI - Python Version](https://img.shields.io/badge/python-%3E%3D%203.10-blue)](https://pypi.org/project/nuspace/)
28
+ [![PyPI Package](https://img.shields.io/pypi/v/nuspace?color=yellow)](https://pypi.org/project/nuspace/)
29
+ [![License](https://img.shields.io/badge/License-AGPL%20v3-orange.svg)](https://www.gnu.org/licenses/agpl-3.0)
30
+ [![PyPI Downloads](https://img.shields.io/pypi/dw/nuspace?color=green)](https://pypi.org/project/nuspace/)
31
+
32
+ </div>
33
+
34
+ ---
35
+
36
+ <h3 align="center">
37
+ <a href="#ℹ️-about"><b>About</b></a> &bull;
38
+ <a href="#quickstart"><b>Quickstart</b></a> &bull;
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
+ [![nuspace](https://img.shields.io/badge/built%20with-nuspace-%237A4CE0)](https://github.com/nustackdev/nuspace)
113
+
114
+ ```
115
+ [![nuspace](https://img.shields.io/badge/built%20with-nuspace-%237A4CE0)](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 nuverse and nothing else.
1
+ """A space in the browser, with whatever extensions are installed.
2
2
 
3
- Every Plane and snippet comes from nuverse, found through its entry point. The
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.2"
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.2",
18
- "nustd[kv,ui,valkey,mp_pool,proxy]>=0.6.2",
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.2",
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.2",
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.host.cli:main"
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 distributions (nuverse, nuspace-ui), each shipped
78
- # from its own directory on its own tag.
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
- nucli = { path = "../nu/pkgs/nucli", editable = true }
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
- "nucli",
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.host import Extension, open_space
19
- from nuspace.ops import TEXT, Plane, Snippet, env
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"]
@@ -1,4 +1,4 @@
1
- """Enables ``python -m nuspace.host.cli``.
1
+ """Enables ``python -m nuspace._cli``.
2
2
 
3
3
  The guard is load bearing: workers are spawned, and a child re-imports
4
4
  whatever ``__main__`` is. Without it, opening a space forks forever.
@@ -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)