nuspace 0.3.0__tar.gz → 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. {nuspace-0.3.0 → nuspace-0.4.0}/.github/workflows/publish-nuspace-ui.yml +8 -8
  2. {nuspace-0.3.0 → nuspace-0.4.0}/.github/workflows/publish-nuspace.yml +12 -11
  3. nuspace-0.4.0/.github/workflows/publish-nuverse.yml +88 -0
  4. {nuspace-0.3.0 → nuspace-0.4.0}/.gitignore +1 -1
  5. {nuspace-0.3.0 → nuspace-0.4.0}/CHANGELOG.md +73 -2
  6. {nuspace-0.3.0 → nuspace-0.4.0}/Makefile +9 -9
  7. {nuspace-0.3.0 → nuspace-0.4.0}/PKG-INFO +8 -8
  8. nuspace-0.4.0/README.md +10 -0
  9. nuspace-0.4.0/examples/space.py +35 -0
  10. {nuspace-0.3.0 → nuspace-0.4.0}/pyproject.toml +34 -13
  11. nuspace-0.4.0/src/nuspace/__init__.py +39 -0
  12. nuspace-0.4.0/src/nuspace/host/__init__.py +21 -0
  13. nuspace-0.4.0/src/nuspace/host/cli/__init__.py +10 -0
  14. nuspace-0.4.0/src/nuspace/host/cli/__main__.py +11 -0
  15. nuspace-0.4.0/src/nuspace/host/cli/main.py +103 -0
  16. nuspace-0.4.0/src/nuspace/host/registry.py +141 -0
  17. nuspace-0.4.0/src/nuspace/host/space.py +167 -0
  18. nuspace-0.4.0/src/nuspace/ops/__init__.py +116 -0
  19. nuspace-0.4.0/src/nuspace/ops/cell.py +224 -0
  20. nuspace-0.4.0/src/nuspace/ops/extend.py +140 -0
  21. nuspace-0.4.0/src/nuspace/ops/kernel.py +322 -0
  22. nuspace-0.4.0/src/nuspace/ops/pin.py +62 -0
  23. nuspace-0.4.0/src/nuspace/ops/plane.py +194 -0
  24. nuspace-0.4.0/src/nuspace/ops/read.py +146 -0
  25. nuspace-0.4.0/src/nuspace/ops/settings.py +29 -0
  26. nuspace-0.4.0/src/nuspace/ops/state.py +47 -0
  27. nuspace-0.4.0/src/nuspace/ops/tree.py +114 -0
  28. nuspace-0.4.0/src/nuspace/ops/utils.py +240 -0
  29. nuspace-0.4.0/src/nuspace/shapes/__init__.py +99 -0
  30. nuspace-0.4.0/src/nuspace/shapes/cell.py +46 -0
  31. nuspace-0.4.0/src/nuspace/shapes/connection.py +22 -0
  32. nuspace-0.4.0/src/nuspace/shapes/kernel.py +143 -0
  33. nuspace-0.4.0/src/nuspace/shapes/plane.py +49 -0
  34. nuspace-0.4.0/src/nuspace/shapes/reroot.py +105 -0
  35. nuspace-0.4.0/src/nuspace/shapes/space.py +87 -0
  36. nuspace-0.4.0/src/nuspace/shapes/state.py +39 -0
  37. nuspace-0.4.0/src/nuspace/shapes/tree.py +23 -0
  38. nuspace-0.4.0/src/nuspace/system/__init__.py +14 -0
  39. nuspace-0.4.0/src/nuspace/system/devices/__init__.py +10 -0
  40. nuspace-0.4.0/src/nuspace/system/devices/web/__init__.py +73 -0
  41. nuspace-0.4.0/src/nuspace/system/devices/web/device.py +255 -0
  42. nuspace-0.4.0/src/nuspace/system/devices/web/env.py +67 -0
  43. nuspace-0.4.0/src/nuspace/system/devices/web/session.py +250 -0
  44. nuspace-0.4.0/src/nuspace/system/devices/web/shell.py +120 -0
  45. nuspace-0.4.0/src/nuspace/system/devices/web/sidebar/__init__.py +53 -0
  46. nuspace-0.4.0/src/nuspace/system/devices/web/sidebar/feed.py +345 -0
  47. nuspace-0.4.0/src/nuspace/system/devices/web/sidebar/interactions.py +118 -0
  48. nuspace-0.4.0/src/nuspace/system/devices/web/sidebar/ref.py +81 -0
  49. nuspace-0.4.0/src/nuspace/system/devices/web/utils.py +240 -0
  50. nuspace-0.4.0/src/nuspace/system/devices/web/viewer/__init__.py +68 -0
  51. nuspace-0.4.0/src/nuspace/system/devices/web/viewer/feed.py +418 -0
  52. nuspace-0.4.0/src/nuspace/system/devices/web/viewer/interactions.py +153 -0
  53. nuspace-0.4.0/src/nuspace/system/devices/web/viewer/ref.py +95 -0
  54. nuspace-0.4.0/src/nuspace/system/home.py +340 -0
  55. nuspace-0.4.0/src/nuspace/system/kernel/__init__.py +59 -0
  56. nuspace-0.4.0/src/nuspace/system/kernel/body.py +215 -0
  57. nuspace-0.4.0/src/nuspace/system/kernel/dispatch.py +88 -0
  58. nuspace-0.4.0/src/nuspace/system/kernel/envs.py +102 -0
  59. nuspace-0.4.0/src/nuspace/system/kernel/kernel.py +59 -0
  60. nuspace-0.4.0/src/nuspace/system/kernel/out.py +268 -0
  61. nuspace-0.4.0/src/nuspace/system/kernel/reconcile.py +62 -0
  62. nuspace-0.4.0/src/nuspace/system/kernel/space.py +257 -0
  63. nuspace-0.4.0/src/nuspace/system/kernel/utils.py +57 -0
  64. nuspace-0.4.0/src/nuspace/system/kernel/workers.py +296 -0
  65. nuspace-0.4.0/src/nuspace/system/services/__init__.py +40 -0
  66. nuspace-0.4.0/src/nuspace/system/services/bootstrap.py +62 -0
  67. nuspace-0.4.0/src/nuspace/system/services/init.py +117 -0
  68. nuspace-0.4.0/src/nuspace/system/services/nav.py +219 -0
  69. nuspace-0.4.0/src/nuspace/system/services/reload.py +101 -0
  70. nuspace-0.4.0/src/nuspace/system/services/supervisor.py +337 -0
  71. nuspace-0.4.0/src/nuspace/system/settings.py +75 -0
  72. nuspace-0.4.0/src/nuspace/system/utils.py +141 -0
  73. nuspace-0.4.0/tests/_lib/_support/__init__.py +1 -0
  74. nuspace-0.4.0/tests/_lib/_support/kernel.py +149 -0
  75. nuspace-0.4.0/tests/_lib/_support/kernel_envs.py +42 -0
  76. nuspace-0.4.0/tests/conftest.py +84 -0
  77. nuspace-0.4.0/tests/nuspace/test_home.py +319 -0
  78. nuspace-0.4.0/tests/nuspace/test_host.py +271 -0
  79. nuspace-0.4.0/tests/nuspace/test_kernel.py +264 -0
  80. nuspace-0.4.0/tests/nuspace/test_ops_kernel.py +162 -0
  81. nuspace-0.4.0/tests/nuspace/test_ops_state.py +180 -0
  82. nuspace-0.4.0/tests/nuspace/test_ops_structure.py +433 -0
  83. nuspace-0.4.0/tests/nuspace/test_packaging.py +136 -0
  84. nuspace-0.4.0/tests/nuspace/test_services.py +421 -0
  85. nuspace-0.4.0/tests/nuspace/test_settings.py +94 -0
  86. nuspace-0.4.0/tests/nuspace/test_shapes.py +231 -0
  87. nuspace-0.4.0/tests/nuspace/test_web.py +670 -0
  88. nuspace-0.4.0/tests/nuverse/test_planes.py +283 -0
  89. nuspace-0.4.0/tests/nuverse/test_snippets.py +186 -0
  90. nuspace-0.3.0/README.md +0 -10
  91. nuspace-0.3.0/examples/headless.py +0 -277
  92. nuspace-0.3.0/examples/web.py +0 -141
  93. nuspace-0.3.0/src/nuspace/__init__.py +0 -82
  94. nuspace-0.3.0/src/nuspace/cli/__init__.py +0 -11
  95. nuspace-0.3.0/src/nuspace/cli/__main__.py +0 -11
  96. nuspace-0.3.0/src/nuspace/cli/cell.py +0 -175
  97. nuspace-0.3.0/src/nuspace/cli/main.py +0 -71
  98. nuspace-0.3.0/src/nuspace/cli/plane.py +0 -175
  99. nuspace-0.3.0/src/nuspace/cli/space.py +0 -212
  100. nuspace-0.3.0/src/nuspace/cli/utils.py +0 -97
  101. nuspace-0.3.0/src/nuspace/drivers/__init__.py +0 -25
  102. nuspace-0.3.0/src/nuspace/drivers/headless.py +0 -81
  103. nuspace-0.3.0/src/nuspace/drivers/web.py +0 -234
  104. nuspace-0.3.0/src/nuspace/exec/__init__.py +0 -51
  105. nuspace-0.3.0/src/nuspace/exec/cell.py +0 -300
  106. nuspace-0.3.0/src/nuspace/exec/plane.py +0 -240
  107. nuspace-0.3.0/src/nuspace/exec/space.py +0 -75
  108. nuspace-0.3.0/src/nuspace/exec/utils.py +0 -78
  109. nuspace-0.3.0/src/nuspace/ops/__init__.py +0 -158
  110. nuspace-0.3.0/src/nuspace/ops/cell.py +0 -494
  111. nuspace-0.3.0/src/nuspace/ops/chat.py +0 -251
  112. nuspace-0.3.0/src/nuspace/ops/groups.py +0 -868
  113. nuspace-0.3.0/src/nuspace/ops/plane.py +0 -349
  114. nuspace-0.3.0/src/nuspace/ops/space.py +0 -102
  115. nuspace-0.3.0/src/nuspace/ops/templates.py +0 -162
  116. nuspace-0.3.0/src/nuspace/ops/utils.py +0 -103
  117. nuspace-0.3.0/src/nuspace/presets.py +0 -134
  118. nuspace-0.3.0/src/nuspace/shapes.py +0 -256
  119. nuspace-0.3.0/src/nuspace/space.py +0 -354
  120. nuspace-0.3.0/src/nuspace/web/__init__.py +0 -61
  121. nuspace-0.3.0/src/nuspace/web/route.py +0 -112
  122. nuspace-0.3.0/src/nuspace/web/session.py +0 -153
  123. nuspace-0.3.0/src/nuspace/web/shell.py +0 -121
  124. nuspace-0.3.0/src/nuspace/web/sidebar/__init__.py +0 -44
  125. nuspace-0.3.0/src/nuspace/web/sidebar/driver.py +0 -232
  126. nuspace-0.3.0/src/nuspace/web/sidebar/interactions.py +0 -123
  127. nuspace-0.3.0/src/nuspace/web/sidebar/ref.py +0 -60
  128. nuspace-0.3.0/src/nuspace/web/utils.py +0 -243
  129. nuspace-0.3.0/src/nuspace/web/viewer/__init__.py +0 -57
  130. nuspace-0.3.0/src/nuspace/web/viewer/driver.py +0 -322
  131. nuspace-0.3.0/src/nuspace/web/viewer/interactions.py +0 -138
  132. nuspace-0.3.0/src/nuspace/web/viewer/ref.py +0 -179
  133. nuspace-0.3.0/tests/test_chat.py +0 -252
  134. nuspace-0.3.0/tests/test_groups.py +0 -153
  135. nuspace-0.3.0/ts/.gitignore +0 -26
  136. nuspace-0.3.0/ts/biome.json +0 -63
  137. nuspace-0.3.0/ts/index.html +0 -12
  138. nuspace-0.3.0/ts/package-lock.json +0 -7603
  139. nuspace-0.3.0/ts/package.json +0 -47
  140. nuspace-0.3.0/ts/pyproject.toml +0 -20
  141. nuspace-0.3.0/ts/src/App.tsx +0 -52
  142. nuspace-0.3.0/ts/src/app/connect.ts +0 -129
  143. nuspace-0.3.0/ts/src/app/ids.ts +0 -26
  144. nuspace-0.3.0/ts/src/app/local.ts +0 -68
  145. nuspace-0.3.0/ts/src/app/router.ts +0 -81
  146. nuspace-0.3.0/ts/src/app/surfaces.ts +0 -47
  147. nuspace-0.3.0/ts/src/app/theme.ts +0 -77
  148. nuspace-0.3.0/ts/src/app/wire.ts +0 -35
  149. nuspace-0.3.0/ts/src/components/index.ts +0 -17
  150. nuspace-0.3.0/ts/src/components/section-status-dot.tsx +0 -108
  151. nuspace-0.3.0/ts/src/design/document.ts +0 -510
  152. nuspace-0.3.0/ts/src/design/index.ts +0 -33
  153. nuspace-0.3.0/ts/src/design/rail.ts +0 -242
  154. nuspace-0.3.0/ts/src/design/section-status.ts +0 -155
  155. nuspace-0.3.0/ts/src/design/shell.ts +0 -47
  156. nuspace-0.3.0/ts/src/design/tokens.css +0 -211
  157. nuspace-0.3.0/ts/src/index.css +0 -39
  158. nuspace-0.3.0/ts/src/main.tsx +0 -21
  159. nuspace-0.3.0/ts/src/refs/register.ts +0 -37
  160. nuspace-0.3.0/ts/src/refs/route.ts +0 -48
  161. nuspace-0.3.0/ts/src/refs/sidebar/Rail.tsx +0 -618
  162. nuspace-0.3.0/ts/src/refs/sidebar/footer.tsx +0 -61
  163. nuspace-0.3.0/ts/src/refs/sidebar/header.tsx +0 -15
  164. nuspace-0.3.0/ts/src/refs/sidebar/ops.ts +0 -40
  165. nuspace-0.3.0/ts/src/refs/sidebar/roving-focus.ts +0 -90
  166. nuspace-0.3.0/ts/src/refs/sidebar/row-input.tsx +0 -59
  167. nuspace-0.3.0/ts/src/refs/sidebar/row.tsx +0 -144
  168. nuspace-0.3.0/ts/src/refs/sidebar/sidebar.tsx +0 -60
  169. nuspace-0.3.0/ts/src/refs/sidebar/state.ts +0 -67
  170. nuspace-0.3.0/ts/src/refs/sidebar/types.ts +0 -127
  171. nuspace-0.3.0/ts/src/refs/viewer/Canvas.tsx +0 -1367
  172. nuspace-0.3.0/ts/src/refs/viewer/Code.tsx +0 -239
  173. nuspace-0.3.0/ts/src/refs/viewer/Program.tsx +0 -113
  174. nuspace-0.3.0/ts/src/refs/viewer/ProseRef.test.tsx +0 -204
  175. nuspace-0.3.0/ts/src/refs/viewer/ProseRef.tsx +0 -606
  176. nuspace-0.3.0/ts/src/refs/viewer/Slash.tsx +0 -263
  177. nuspace-0.3.0/ts/src/refs/viewer/blocks.ts +0 -89
  178. nuspace-0.3.0/ts/src/refs/viewer/monaco-impl.ts +0 -92
  179. nuspace-0.3.0/ts/src/refs/viewer/monaco.ts +0 -50
  180. nuspace-0.3.0/ts/src/refs/viewer/ops.ts +0 -68
  181. nuspace-0.3.0/ts/src/refs/viewer/prose.ts +0 -68
  182. nuspace-0.3.0/ts/src/refs/viewer/state.ts +0 -255
  183. nuspace-0.3.0/ts/src/refs/viewer/types.ts +0 -100
  184. nuspace-0.3.0/ts/src/refs/viewer/viewer.tsx +0 -91
  185. nuspace-0.3.0/ts/src/vite-env.d.ts +0 -5
  186. nuspace-0.3.0/ts/tsconfig.app.json +0 -31
  187. nuspace-0.3.0/ts/tsconfig.json +0 -10
  188. nuspace-0.3.0/ts/tsconfig.node.json +0 -24
  189. nuspace-0.3.0/ts/vite.config.ts +0 -55
  190. nuspace-0.3.0/ts/vitest.config.ts +0 -44
  191. {nuspace-0.3.0 → nuspace-0.4.0}/.pre-commit-config.yaml +0 -0
  192. {nuspace-0.3.0 → nuspace-0.4.0}/LICENSE.md +0 -0
@@ -3,9 +3,9 @@
3
3
  #
4
4
  # The nuspace-ui wheel is nothing but the compiled vite SPA, force-included at
5
5
  # the wheel path `nuspace_ui/build/`. It carries no python source and no
6
- # dependencies. The runtime locates it with `import nuspace_ui` -- see
7
- # `_bundled_static()` in src/nuspace/web/serve/app.py -- and skips the static
8
- # mount entirely if it is not installed.
6
+ # dependencies. The web device hands `static="nuspace_ui"` to nustd.ws_server,
7
+ # which locates it by import (see `serve_web` in
8
+ # src/nuspace/system/devices/web/device.py).
9
9
  #
10
10
  # Keeping the bundle in its own distribution is the point: PyPI caps project
11
11
  # size, and a compiled SPA rebuilt on every UI tweak would burn through the
@@ -20,8 +20,8 @@
20
20
  # Environment name: (leave blank)
21
21
  #
22
22
  # Release flow:
23
- # 1. Bump `version` in both `ts/pyproject.toml` and
24
- # `ts/package.json` (keep them equal).
23
+ # 1. Bump `version` in both `pkgs/ts/nuspace-ui/pyproject.toml`
24
+ # and `pkgs/ts/nuspace-ui/package.json` (keep them equal).
25
25
  # 2. Commit and push to main.
26
26
  # 3. `git tag nuspace-ui@X.Y.Z && git push origin nuspace-ui@X.Y.Z`.
27
27
  name: Publish nuspace-ui to PyPI
@@ -40,7 +40,7 @@ concurrency:
40
40
  cancel-in-progress: false
41
41
 
42
42
  env:
43
- UI_DIR: ts
43
+ UI_DIR: pkgs/ts/nuspace-ui
44
44
 
45
45
  jobs:
46
46
  publish:
@@ -53,7 +53,7 @@ jobs:
53
53
  with:
54
54
  node-version: 24
55
55
  cache: npm
56
- cache-dependency-path: ts/package-lock.json
56
+ cache-dependency-path: pkgs/ts/nuspace-ui/package-lock.json
57
57
 
58
58
  - uses: actions/setup-python@v5
59
59
  with:
@@ -115,5 +115,5 @@ jobs:
115
115
  if: startsWith(github.ref, 'refs/tags/nuspace-ui@')
116
116
  uses: pypa/gh-action-pypi-publish@release/v1
117
117
  with:
118
- packages-dir: ts/wheel-dist
118
+ packages-dir: pkgs/ts/nuspace-ui/wheel-dist
119
119
  skip-existing: true
@@ -13,19 +13,20 @@
13
13
  # Workflow name: publish-nuspace.yml
14
14
  # Environment name: (leave blank)
15
15
  #
16
- # Two distributions ship from this repo, on independent tags:
17
- # . -> nuspace (the runtime + the `nuspace` command)
18
- # ts -> nuspace-ui (the compiled vite bundle)
16
+ # Three distributions ship from this repo, on independent tags:
17
+ # . -> nuspace (the runtime + the `nuspace` command)
18
+ # pkgs/nuverse -> nuverse (the extensions: Planes, snippets)
19
+ # pkgs/ts/nuspace-ui -> nuspace-ui (the compiled vite bundle)
19
20
  #
20
- # They version independently. `nuspace` hard-depends on `nuspace-ui>=X.Y.Z`, so
21
- # a python release can require a newer bundle, but a bundle-only fix ships on
22
- # its own tag without republishing this wheel.
21
+ # They version independently. `nuspace` hard-depends on `nuspace-ui>=X.Y.Z` and
22
+ # `nuverse>=X.Y.Z`, so a python release can require a newer bundle, but a
23
+ # bundle-only fix ships on its own tag without republishing this wheel.
23
24
  #
24
- # The wheel deliberately excludes `ts/**` (see the hatch config
25
- # in pyproject.toml). The compiled assets live in the nuspace-ui wheel and are
26
- # found at runtime by `import nuspace_ui` -- see `_bundled_static()` in
27
- # src/nuspace/web/serve/app.py. So this build needs no node toolchain, even
28
- # though an install always pulls the bundle.
25
+ # The wheel deliberately ships `src/nuspace` alone, `pkgs/**` stays out (see
26
+ # the hatch config in pyproject.toml). The compiled assets live in the
27
+ # nuspace-ui wheel and are found at runtime by import -- see `serve_web` in
28
+ # src/nuspace/system/devices/web/device.py. So this build needs no node
29
+ # toolchain, even though an install always pulls the bundle.
29
30
  #
30
31
  # Ordering on a coordinated release: push the `nuspace-ui@` tag first, so the
31
32
  # bundle is on the index before the wheel that requires it.
@@ -0,0 +1,88 @@
1
+ # Publishes the `nuverse` distribution to PyPI on a tag push like `nuverse@0.1.0`.
2
+ # Manual "Run workflow" dispatch builds only, unless you tick `publish`.
3
+ #
4
+ # nuverse is the extensions package: the Planes (`+`) and snippets (`/`) a space
5
+ # offers out of the box. nuspace finds it through the `nuspace.extensions`
6
+ # entry point and hard-depends on it. It carries python source only, no node
7
+ # toolchain needed.
8
+ #
9
+ # `nuspace` tags own release semantics for the repo (GitHub Release). This tag
10
+ # does not cut a release, same as `nuspace-ui`.
11
+ #
12
+ # Setup once (PyPI trusted publisher / OIDC, no secrets):
13
+ # pypi.org -> account -> Publishing -> Add pending publisher
14
+ # PyPI project name: nuverse
15
+ # Owner: nustackdev
16
+ # Repository name: nuspace
17
+ # Workflow name: publish-nuverse.yml
18
+ # Environment name: (leave blank)
19
+ #
20
+ # Ordering on a coordinated release: nuverse depends on nuspace and nuspace on
21
+ # nuverse, so push `nuverse@` first, then `nuspace@`. pip resolves the cycle
22
+ # once both are on the index.
23
+ #
24
+ # Release flow:
25
+ # 1. Bump `version` in `pkgs/nuverse/pyproject.toml`.
26
+ # 2. Commit and push to main.
27
+ # 3. `git tag nuverse@X.Y.Z && git push origin nuverse@X.Y.Z`.
28
+ name: Publish nuverse to PyPI
29
+
30
+ on:
31
+ push:
32
+ tags: ["nuverse@*"]
33
+ workflow_dispatch:
34
+ inputs:
35
+ publish:
36
+ description: "Publish to PyPI (otherwise build only)"
37
+ type: boolean
38
+ default: false
39
+
40
+ permissions:
41
+ contents: read
42
+ id-token: write # PyPI trusted publishing (OIDC)
43
+
44
+ concurrency:
45
+ group: publish-nuverse
46
+ cancel-in-progress: false
47
+
48
+ env:
49
+ PKG_DIR: pkgs/nuverse
50
+
51
+ jobs:
52
+ publish:
53
+ runs-on: ubuntu-latest
54
+ timeout-minutes: 10
55
+ steps:
56
+ - uses: actions/checkout@v4
57
+
58
+ - uses: actions/setup-python@v5
59
+ with:
60
+ python-version: "3.12"
61
+
62
+ - name: install uv
63
+ uses: astral-sh/setup-uv@v5
64
+
65
+ - name: verify tag matches pyproject.toml version
66
+ if: startsWith(github.ref, 'refs/tags/nuverse@')
67
+ working-directory: ${{ env.PKG_DIR }}
68
+ run: |
69
+ TAG_VERSION="${GITHUB_REF#refs/tags/nuverse@}"
70
+ PKG_VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
71
+ if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
72
+ echo "tag nuverse@$TAG_VERSION does not match pyproject.toml version $PKG_VERSION"
73
+ exit 1
74
+ fi
75
+
76
+ # The workspace source for nuspace is dev-only; a hatchling build is
77
+ # metadata-only, so the wheel carries the plain PyPI requirement.
78
+ - name: build distribution
79
+ working-directory: ${{ env.PKG_DIR }}
80
+ run: uv build --out-dir dist
81
+
82
+ - name: publish nuverse
83
+ if: >-
84
+ startsWith(github.ref, 'refs/tags/nuverse@') || inputs.publish
85
+ uses: pypa/gh-action-pypi-publish@release/v1
86
+ with:
87
+ packages-dir: pkgs/nuverse/dist
88
+ skip-existing: true
@@ -95,5 +95,5 @@ src/nuspace/web/ui/dist/*
95
95
  !src/nuspace/web/ui/dist/.gitkeep
96
96
 
97
97
  *.db/
98
- # local archive of the v0 prototype (reference only, never edited)
98
+ # Local archive of the v0 prototype (reference only, never edited)
99
99
  _archive/
@@ -2,13 +2,84 @@
2
2
 
3
3
  ## Packages shipped from this repo
4
4
 
5
- - **nuspace** (the runtime, the `nuspace` command) — 0.3.0
6
- - **nuspace-ui** (the compiled web bundle) — 0.3.0
5
+ - **nuspace** (the runtime, the `nuspace` command) — 0.4.0
6
+ - **nuspace-ui** (the compiled web bundle) — 0.4.0
7
+ - **nuverse** (the Planes and snippets a space ships with) — 0.2.0
7
8
 
8
9
  Below is the changelog for **nuspace** - the full commit stream. Newest first.
9
10
  The `nuspace-ui` wheel is the same source tree's vite output and is not tracked
10
11
  separately here.
11
12
 
13
+ ## 0.4.0 — 2026-09-25
14
+
15
+ - Cells and planes still loading show skeletons, not blank space or No view
16
+ - Browser tabs show the open plane's title and emoji, or the nu logo
17
+ - Menus, dialogs, empty states and chips now come from the shared kit
18
+ - Opening a missing or headless plane says so instead of showing an empty page
19
+ - Cells that draw nothing show a quiet No view chip on every plane
20
+ - Drag planes into a split, drag tabs to reorder, cmd-click opens a browser tab
21
+ - Pin planes to a row at the top of the sidebar, reorder them by dragging
22
+ - Home and settings start with their own icons, a house and a gear
23
+ - A settings plane with a telemetry switch, and home lives at its own address
24
+ - Planes write like a document: Enter, Cmd+Enter, Backspace across text cells, and box selection
25
+ - A wider sidebar by default, and clicking a resize handle resets its width
26
+ - The plane icon sits in the gutter beside the title, and the emoji tab opens first
27
+ - Planes lay out on one grid, so gutters never hang past a narrow pane
28
+ - Empty planes show how to start, and the cell menu says when nothing matches
29
+ - Start typing on an empty line and a text cell opens with your words
30
+ - Planes take an icon or emoji, picked from the title or the sidebar menu
31
+ - New cells from a snippet open showing what they draw, not their code
32
+ - Rename a plane by editing its title in place, on any plane
33
+ - New lens snippets browse the current plane, or a cell picked from a dropdown
34
+ - A Lens snippet browses any shape in the store as cascading columns
35
+ - A Jobs plane makes headless planes and sets their code, boot and restart
36
+ - Supervised cells can restart after a fixed delay, so a job can run periodically
37
+ - Plane rows open in split from a hover button, and cut-off names show in tooltips
38
+ - The sidebar shows the nuspace wordmark, and planes no longer jump when scrolling starts
39
+ - A calmer, collapsible sidebar with hover chevrons and GitHub and docs links
40
+ - Tooltips wait a moment before showing, the same everywhere
41
+ - Apps become Planes: registered data seeded with cells, created from one add plane popup
42
+ - The sidebar is one tree of planes, reordered and nested by dragging rows
43
+ - Everything is called a plane or a cell, across the interface, wire and code
44
+ - Interface text, labels and messages now use normal sentence case
45
+ - A home page shows recent pages, a live overview and how to get started
46
+ - Split panes get a tab bar to switch, rename and close them
47
+ - A compact page setting tightens the header and drops the space below
48
+ - Panes get a settings menu, resize handles and side scrolling when crowded
49
+ - Pages keep their own settings, like editable and full width, apart from system ones
50
+ - Open several pages side by side in one tab, each running on its own
51
+ - Watch live runs, workers and planes from their own sidebar pages
52
+ - Tests split per package, with shared helpers in one place
53
+ - One example opens a space with the bundled extensions and nothing else
54
+ - A page opened before it finishes being created still comes up
55
+ - Resize the sidebar, and cell controls show on hover and stay in view
56
+ - A cell finishing no longer breaks drawing for the other cells on its page
57
+ - Every cell renders the same way, and / inserts any registered snippet
58
+ - Publish nuverse on its own tag so the extensions ship separately
59
+ - Pick any registered snippet from the / menu
60
+ - An open page runs every cell as soon as you land on it, even after a restart
61
+ - Ship apps and snippets as nuverse, a separate package found on install
62
+ - Run a cell the moment it is added to an open page, and stop it when removed
63
+ - Forget old browser tabs on open, and give the web example prose and program cells
64
+ - Open a space from one call or the command line, with extensions found on install
65
+ - Serve the browser from a device that tracks tabs and never runs planes
66
+ - Start, restart, reload and route planes through ordinary services on workers
67
+ - Run cells on workers through one kernel that records, stops and reaps every run
68
+ - Add the operations every part of a space is built from
69
+ - Store planes, cells and runs apart, and let a program declare its own typed state
70
+ - Clear the v3 source out of the way for the v4 rewrite
71
+
72
+ ## 0.3.1 — 2026-09-23
73
+
74
+ - Opening a page no longer slows down with each extra cell on it
75
+ - Navigating away clears the old page at once instead of blinking through it
76
+ - Keep workers ready in advance, so opening a plane no longer waits for one to start
77
+ - Draw a page without a web server loaded behind it, so it opens much sooner
78
+ - Let a chat work as long as the work takes, and stop it only when it is stuck
79
+ - Always get a way to say something else, whatever a turn drew
80
+ - Watch a chat work step by step, and never get a broken answer
81
+ - Ask a chat for something and it draws the answer and how you reply
82
+
12
83
  ## 0.3.0 — 2026-09-21
13
84
 
14
85
  - Make a chat, ask it for something, and watch it work the space
@@ -5,7 +5,7 @@ GREEN := \033[0;32m
5
5
  YELLOW := \033[1;33m
6
6
  NC := \033[0m
7
7
 
8
- UI_APP := ts
8
+ UI_DIR := pkgs/ts/nuspace-ui
9
9
 
10
10
  help:
11
11
  @echo "$(BLUE)nuspace$(NC)"
@@ -20,7 +20,7 @@ help:
20
20
  @echo " make test-cov Run tests with coverage"
21
21
  @echo " make test-fast Run tests (fail fast)"
22
22
  @echo ""
23
- @echo "$(GREEN)Code Quality:$(NC)"
23
+ @echo "$(GREEN)Code quality:$(NC)"
24
24
  @echo " make lint Check code with ruff"
25
25
  @echo " make format Format code with ruff"
26
26
  @echo " make check Run format-check + lint"
@@ -28,7 +28,7 @@ help:
28
28
  @echo "$(GREEN)nuspace-ui web:$(NC)"
29
29
  @echo " make web-install npm install in the ui workspace"
30
30
  @echo " make web-dev Run vite dev server"
31
- @echo " make web-build Build the vite bundle into $(UI_APP)/dist"
31
+ @echo " make web-build Build the vite bundle into $(UI_DIR)/dist"
32
32
  @echo ""
33
33
  @echo "$(GREEN)Packages:$(NC)"
34
34
  @echo " make build-nuspace Build the nuspace wheel"
@@ -88,17 +88,17 @@ check: format-check lint
88
88
 
89
89
  web-install:
90
90
  @echo "$(BLUE)Installing ui deps...$(NC)"
91
- cd $(UI_APP) && npm install
91
+ cd $(UI_DIR) && npm install
92
92
  @echo "$(GREEN)Installed$(NC)"
93
93
 
94
94
  web-dev:
95
95
  @echo "$(BLUE)Starting vite dev server...$(NC)"
96
- cd $(UI_APP) && npm run dev
96
+ cd $(UI_DIR) && npm run dev
97
97
 
98
98
  web-build:
99
99
  @echo "$(BLUE)Building nuspace-ui web bundle...$(NC)"
100
- cd $(UI_APP) && npm run build
101
- @echo "$(GREEN)Built: $(UI_APP)/dist/$(NC)"
100
+ cd $(UI_DIR) && npm run build
101
+ @echo "$(GREEN)Built: $(UI_DIR)/dist/$(NC)"
102
102
 
103
103
  build-nuspace:
104
104
  @echo "$(BLUE)Building nuspace wheel...$(NC)"
@@ -109,8 +109,8 @@ build-ui: web-build
109
109
  @echo "$(BLUE)Building nuspace-ui web-bundle wheel...$(NC)"
110
110
  # --out-dir keeps the wheel out of dist/, which IS the vite output we
111
111
  # force-include into it. Writing there packages the last wheel into the next.
112
- cd $(UI_APP) && uv build --wheel --out-dir wheel-dist
113
- @echo "$(GREEN)Built: $(UI_APP)/wheel-dist/$(NC)"
112
+ cd $(UI_DIR) && uv build --wheel --out-dir wheel-dist
113
+ @echo "$(GREEN)Built: $(UI_DIR)/wheel-dist/$(NC)"
114
114
 
115
115
  build-all: build-nuspace build-ui
116
116
  @echo "$(GREEN)Both wheels built$(NC)"
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: nuspace
3
- Version: 0.3.0
4
- Summary: Nu runtime built on Nu. A self-hosted programmable space that runs Nu apps in a tree of containers and applications.
3
+ Version: 0.4.0
4
+ Summary: Nu runtime built on Nu. A self-hosted programmable space that runs Nu programs as a tree of planes and cells.
5
5
  Project-URL: Repository, https://github.com/nustackdev/nuspace
6
6
  Author-email: Gor Arakelyan <gorarkln@gmail.com>
7
7
  License-Expression: AGPL-3.0-or-later
@@ -16,10 +16,10 @@ Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: 3.13
17
17
  Requires-Python: >=3.10
18
18
  Requires-Dist: click>=8.0
19
- Requires-Dist: nuagent>=0.1.3
20
- Requires-Dist: nucore>=0.5.2
21
- Requires-Dist: nuspace-ui>=0.3.0
22
- Requires-Dist: nustd[all]>=0.5.2
19
+ Requires-Dist: nucore>=0.5.3
20
+ Requires-Dist: nuspace-ui>=0.4.0
21
+ Requires-Dist: nustd[all]>=0.5.3
22
+ Requires-Dist: nuverse>=0.2.0
23
23
  Requires-Dist: rich-click>=1.6
24
24
  Requires-Dist: rich>=10.7
25
25
  Requires-Dist: typing-extensions>=4.7.0
@@ -29,8 +29,8 @@ Description-Content-Type: text/markdown
29
29
 
30
30
  Nu runtime built on Nu. Self-hosted.
31
31
 
32
- A tree of containers and applications.
33
- The runtime evaluates Nu apps, provides the fabrics they use (nustd.kv, nustd.proxy, nustd.mp_pool, nulog, nustd.ui), and renders a human interface for the ones that opt in.
32
+ A tree of planes, each a group of cells.
33
+ The runtime evaluates Nu programs, provides the fabrics they use (nustd.kv, nustd.proxy, nustd.mp_pool, nulog, nustd.ui), and renders a human interface for the ones that opt in.
34
34
 
35
35
  ## License
36
36
 
@@ -0,0 +1,10 @@
1
+ # nuspace
2
+
3
+ Nu runtime built on Nu. Self-hosted.
4
+
5
+ A tree of planes, each a group of cells.
6
+ The runtime evaluates Nu programs, provides the fabrics they use (nustd.kv, nustd.proxy, nustd.mp_pool, nulog, nustd.ui), and renders a human interface for the ones that opt in.
7
+
8
+ ## License
9
+
10
+ GNU Affero General Public License v3.0. See [LICENSE.md](LICENSE.md).
@@ -0,0 +1,35 @@
1
+ """A space in the browser, with nuverse and nothing else.
2
+
3
+ Every Plane and snippet comes from nuverse, found through its entry point. The
4
+ store is ``examples/space.db``, kept between runs.
5
+
6
+ Run it::
7
+
8
+ python examples/space.py
9
+
10
+ A browser opens on http://127.0.0.1:8080. Ctrl+C stops it.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import logging
16
+ from pathlib import Path
17
+
18
+ import nu
19
+ import nuspace
20
+
21
+
22
+ # Closing the space drops sockets under workers still holding them. Expected.
23
+ # At module scope so spawned workers, which import this file, are quiet too.
24
+ logging.getLogger("invisibles").setLevel(logging.CRITICAL)
25
+
26
+
27
+ STORE = str(Path(__file__).parent / "space.db")
28
+
29
+
30
+ if __name__ == "__main__":
31
+ # Load bearing: workers are spawned and re-import __main__.
32
+ try:
33
+ nu.run_in_loop(nuspace.open_space(STORE))
34
+ except KeyboardInterrupt:
35
+ print("stopped")
@@ -4,25 +4,29 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "nuspace"
7
- version = "0.3.0"
8
- description = "Nu runtime built on Nu. A self-hosted programmable space that runs Nu apps in a tree of containers and applications."
7
+ version = "0.4.0"
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"
11
11
  authors = [{ name = "Gor Arakelyan", email = "gorarkln@gmail.com" }]
12
12
  requires-python = ">=3.10"
13
13
  dependencies = [
14
- # The whole stack, every extra. A space runs arbitrary Nu apps and its own
15
- # sections in pool workers, so it reaches most fabrics: kv for the store,
14
+ # The whole stack, every extra. A space runs arbitrary Nu programs and its own
15
+ # services in pool workers, so it reaches most fabrics: kv for the store,
16
16
  # ui for the browser, proxy (invisibles) for the worker's session, mp_pool
17
17
  # for the workers themselves. Picking extras just means discovering the
18
18
  # missing one at import time.
19
- "nucore>=0.5.2",
20
- "nustd[all]>=0.5.2",
19
+ "nucore>=0.5.3",
20
+ "nustd[all]>=0.5.3",
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.3.0",
25
- "nuagent>=0.1.3",
24
+ "nuspace-ui>=0.4.0",
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.2.0",
26
30
  "typing-extensions>=4.7.0",
27
31
  "click>=8.0",
28
32
  "rich>=10.7",
@@ -52,23 +56,33 @@ classifiers = [
52
56
  Repository = "https://github.com/nustackdev/nuspace"
53
57
 
54
58
  [project.scripts]
55
- nuspace = "nuspace.cli:main"
59
+ nuspace = "nuspace.host.cli:main"
56
60
 
57
61
  [tool.hatch.build.targets.wheel]
62
+ # Whole directories, not python files: the agent's system prompt is prose in
63
+ # `nuspace/agent/prompt/text/*.md`, read at runtime through
64
+ # importlib.resources. hatchling ships every file under a listed package, so
65
+ # this needs no data entry of its own -- but adding an `include` or
66
+ # `only-include` here would drop the prose and leave a wheel whose chats
67
+ # raise on their first message. Don't.
58
68
  packages = ["src/nuspace"]
59
69
 
60
70
  [tool.hatch.build.targets.sdist]
71
+ # pkgs/ holds the sibling distributions (nuverse, nuspace-ui), each shipped
72
+ # from its own directory on its own tag.
61
73
  exclude = [
62
- "ts/node_modules",
63
- "ts/dist",
74
+ "pkgs",
64
75
  ]
65
76
 
77
+ [tool.uv.workspace]
78
+ members = ["pkgs/nuverse"]
79
+
66
80
  [tool.uv.sources]
67
- nuspace-ui = { path = "./ts" }
81
+ nuverse = { workspace = true }
82
+ nuspace-ui = { path = "./pkgs/ts/nuspace-ui" }
68
83
  nucore = { path = "../nu", editable = true }
69
84
  nustd = { path = "../nu/pkgs/nustd", editable = true }
70
85
  nucli = { path = "../nu/pkgs/nucli", editable = true }
71
- nuagent = { path = "../nuagent", editable = true }
72
86
 
73
87
  [tool.uv]
74
88
  default-groups = ["dev"]
@@ -88,6 +102,11 @@ dev = [
88
102
  testpaths = [
89
103
  "tests",
90
104
  ]
105
+ # `tests/_lib` is the only test directory on sys.path, and `_support` the only
106
+ # thing in it: shared helpers, importable by spawned workers too.
107
+ pythonpath = [
108
+ "tests/_lib",
109
+ ]
91
110
  python_files = ["test_*.py"]
92
111
  python_classes = ["Test*"]
93
112
  python_functions = ["test_*"]
@@ -128,6 +147,7 @@ line-length = 100
128
147
  target-version = "py310"
129
148
  src = [
130
149
  "src",
150
+ "pkgs/nuverse/src",
131
151
  ]
132
152
  extend-exclude = [".venv", "build", "dist", "*.egg-info"]
133
153
 
@@ -170,6 +190,7 @@ convention = "google"
170
190
  [tool.ruff.lint.isort]
171
191
  known-first-party = [
172
192
  "nuspace",
193
+ "nuverse",
173
194
  "nu",
174
195
  "nustd",
175
196
  "nucli",
@@ -0,0 +1,39 @@
1
+ """nuspace: runs Nu programs as a space of planes and cells.
2
+
3
+ What a host and a program need, without knowing the layers:
4
+
5
+ - :func:`open_space`, and :class:`Extension`, :class:`Plane`, :class:`Snippet`
6
+ to register (the store's own plane shape is ``shapes.Plane``), and
7
+ :data:`TEXT`, the name reserved for the text snippet;
8
+ - :class:`CellState`, :class:`PlaneState`, so a program says
9
+ ``class Tick(nuspace.CellState)``;
10
+ - :mod:`ops`, and the few a host reaches for first: :func:`boot`,
11
+ :func:`unboot`, :func:`supervise`, :func:`env`.
12
+
13
+ Workers import this package: nothing here may pull in a server.
14
+ """
15
+
16
+ from nuspace import ops, shapes
17
+ from nuspace.host import Extension, open_space
18
+ from nuspace.ops import TEXT, Plane, Snippet, env
19
+ from nuspace.shapes import CellState, PlaneState, Space
20
+ from nuspace.system.services import boot, supervise, unboot, unsupervise
21
+
22
+
23
+ __all__ = [
24
+ "TEXT",
25
+ "CellState",
26
+ "Extension",
27
+ "Plane",
28
+ "PlaneState",
29
+ "Snippet",
30
+ "Space",
31
+ "boot",
32
+ "env",
33
+ "open_space",
34
+ "ops",
35
+ "shapes",
36
+ "supervise",
37
+ "unboot",
38
+ "unsupervise",
39
+ ]
@@ -0,0 +1,21 @@
1
+ """Layer three: the host composes the system.
2
+
3
+ - :mod:`.registry`: extensions, their discovery, and the merged registry.
4
+ - :mod:`.space`: :func:`open_space`, the whole system in one term.
5
+ - :mod:`.cli`: the ``nuspace`` command. Not imported here: workers import
6
+ :mod:`nuspace`, and the command line is no business of theirs.
7
+ """
8
+
9
+ from .registry import GROUP, Extension, Registry, RegistryWarning, discover
10
+ from .space import open_space, space_registry
11
+
12
+
13
+ __all__ = [
14
+ "GROUP",
15
+ "Extension",
16
+ "Registry",
17
+ "RegistryWarning",
18
+ "discover",
19
+ "open_space",
20
+ "space_registry",
21
+ ]
@@ -0,0 +1,10 @@
1
+ """The ``nuspace`` command: open a space, served in a browser or headless.
2
+
3
+ A space is a directory one process locks at a time, so either command holds
4
+ it for as long as it is up.
5
+ """
6
+
7
+ from .main import cli, main
8
+
9
+
10
+ __all__ = ["cli", "main"]
@@ -0,0 +1,11 @@
1
+ """Enables ``python -m nuspace.host.cli``.
2
+
3
+ The guard is load bearing: workers are spawned, and a child re-imports
4
+ whatever ``__main__`` is. Without it, opening a space forks forever.
5
+ """
6
+
7
+ from .main import main
8
+
9
+
10
+ if __name__ == "__main__":
11
+ main()