@mmmbuto/nexuscrew 0.9.63 → 0.9.65
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.
- package/CHANGELOG.md +14 -0
- package/README.md +9 -21
- package/docs/NOTIFICATIONS.md +34 -0
- package/docs/SECURITY.md +13 -12
- package/frontend/dist/assets/index-DkYRC1vV.js +169 -0
- package/frontend/dist/assets/{index-D1cTtNED.css → index-Dwd37Z_R.css} +2 -2
- package/frontend/dist/index.html +2 -2
- package/frontend/dist/version.json +1 -1
- package/lib/cells/routes.js +37 -3
- package/lib/cli/commands.js +1 -1
- package/lib/config.js +1 -1
- package/lib/fleet/builtin.js +3 -0
- package/lib/fleet/cell-lease-server.js +1 -1
- package/lib/fleet/cell-lease.js +1 -1
- package/lib/fleet/lease-client.js +1 -1
- package/lib/fleet/lease-verifier.js +1 -1
- package/lib/live-host/attest.js +39 -0
- package/lib/live-host/bridge.js +81 -21
- package/lib/live-host/entry.js +49 -0
- package/lib/live-host/registry.js +111 -0
- package/lib/live-host/reserved.js +12 -0
- package/lib/mcp/cells.js +37 -0
- package/lib/mcp/server.js +7 -1
- package/lib/mcp/tools.js +7 -1
- package/lib/notify/ask-relay.js +36 -166
- package/lib/notify/event-feed-asks-routes.js +18 -3
- package/lib/notify/event-feed-client.js +85 -10
- package/lib/notify/event-feed-notices-routes.js +135 -0
- package/lib/notify/event-feed-producers.js +21 -0
- package/lib/notify/event-feed-routes.js +30 -11
- package/lib/notify/notice-dismissal-queue.js +336 -0
- package/lib/notify/notice-dismissals.js +178 -0
- package/lib/notify/notice-relay.js +128 -0
- package/lib/notify/owner-channel.js +172 -0
- package/lib/proxy/federation.js +9 -0
- package/lib/proxy/resource-acl.js +6 -0
- package/lib/server.js +229 -12
- package/lib/tmux/actions.js +1 -1
- package/package.json +2 -2
- package/frontend/dist/assets/index-maPH0v_e.js +0 -169
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to NexusCrew are tracked here.
|
|
4
4
|
|
|
5
|
+
## 0.9.65 — 2026-10-09
|
|
6
|
+
|
|
7
|
+
- **Notifications from a remote node can be cleared locally, one voice or all at once.** Every imported notice offers the same close action asks already have: one request dismisses a single notice or the whole visible set of an owner. The dismissal travels to the owner over the authorized routes and is judged by the origin's view; the owner records it and publishes one `notify-closed` closure per cleared notice, so every receiver empties, including the ones that were not part of the clear. When the owner cannot take it — unreachable, or without the notices surface — the request still succeeds: the node records the intent durably, as pending with a bounded retry or as blocked until the pairing changes, and the record, not the browser, is what keeps the card down. A reload or a restart of the receiving node does not bring a cleared notice back, and once the owner takes the dismissed intent he stops serving those notices himself. "Clear" means the whole visible set of that owner on this node: every notice currently shown for him, cleared in one request inside the owner's per-request budget.
|
|
8
|
+
- **A dismissal queue that cannot persist says so.** The queue still honours a cleared notice in memory when the disk refuses the write, but the operator's answer no longer looks like the durable success: queued answers (the single dismiss and the pending/blocked outcomes of clear-all) carry `durable: false` and a `degraded` reason (`queue-write-failed`, `queue-oversize`, `queue-read-failed`, `queue-schema`) when the queue cannot be written or read. The loss is real and now visible: after a restart the cleared card can come back, and the answer warns about it before that happens. A healthy write clears the flag again, and the answer returns to its normal shape.
|
|
9
|
+
- **A queue file that cannot be read is never overwritten with a partial list.** When the queue file is unreadable, foreign or oversize at the first read, the node retries the read before any write, merges what the disk holds with the dismissals accepted in the meantime, and replays them in order on top of the disk. The queue keeps its bounds (200 records, 64 KiB, 15 minutes): when it is full the oldest records leave, never the dismissal just accepted. While the disk stays unreadable the answers keep declaring `durable: false` and the reason.
|
|
10
|
+
- **A missed closure heals at the next read.** A browser that misses a notice's live closure frame kept the card on screen even after a fresh, complete feed-state read no longer listed the notice. For every owner whose view is fresh and authoritative, the notice panel now reconciles against that read: what the owner no longer serves goes, and a card that arrived while the read was in flight stays. Stale, incomplete or resync-flagged views keep their cards as before.
|
|
11
|
+
- **An owner with a full window is no longer refused as incomplete.** A snapshot page cut exactly at its cap (50 notifications, 100 asks) was marked as incomplete on every full page, so a receiving node refused the snapshot of an owner with a full window, imported nothing and never opened the stream. The marker now means that the source had more entries than the page holds; a page exactly at the cap is whole and accepted, and a page over the cap or flagged for resync is still refused.
|
|
12
|
+
|
|
13
|
+
## 0.9.64 — 2026-10-07
|
|
14
|
+
|
|
15
|
+
- **The active quick list hides stopped cells.** The active mode keeps only live cells and active degraded rows, regardless of each node's saved all or pinned preference; ordering and pins remain intact.
|
|
16
|
+
- **Live has its own directory identity.** A persisted thread registry exposes a reserved Live entry, verifies message labels against the current thread, and removes entries only when the matching thread is gone. The interface shows a Live badge while a thread exists.
|
|
17
|
+
- **Public source and packages use neutral examples.** The README no longer includes screenshots, internal work references have been removed from public files, and source and package checks enforce the publication boundary.
|
|
18
|
+
|
|
5
19
|
## 0.9.63 — 2026-10-07
|
|
6
20
|
|
|
7
21
|
- **Sidebar node names keep their own row.** The mode filter sits below the node name and aligns to the right, leaving the name readable without changing the node controls.
|
package/README.md
CHANGED
|
@@ -19,10 +19,6 @@ stay yours, and your infrastructure stays under your control.
|
|
|
19
19
|
> in what order, and what not to do. Every other NexusCrew skill assumes it,
|
|
20
20
|
> and this README alone does not replace it.
|
|
21
21
|
|
|
22
|
-
<p align="center">
|
|
23
|
-
<img src="docs/img/fleet-deck-desktop.png" width="960" alt="NexusCrew desktop deck with multiple live tmux sessions">
|
|
24
|
-
</p>
|
|
25
|
-
|
|
26
22
|
## One control plane. Every screen.
|
|
27
23
|
|
|
28
24
|
The desktop deck keeps the whole fleet visible. Open any cell from a phone and
|
|
@@ -39,12 +35,6 @@ routed Fleet state while open, keeps a degraded cell visible as a warning, and
|
|
|
39
35
|
has an explicit all-cells view when you need the complete inventory instead of
|
|
40
36
|
a quick switch.
|
|
41
37
|
|
|
42
|
-
<p align="center">
|
|
43
|
-
<img src="docs/img/session-mobile.png" width="360" alt="NexusCrew mobile terminal connected to a real tmux session with touch controls">
|
|
44
|
-
<br>
|
|
45
|
-
<sub><strong>Real tmux on mobile.</strong> Terminal keys, dictation and file handoff stay within reach.</sub>
|
|
46
|
-
</p>
|
|
47
|
-
|
|
48
38
|
## Install in 30 seconds
|
|
49
39
|
|
|
50
40
|
Install the package globally:
|
|
@@ -117,20 +107,18 @@ session ownership to tmux.
|
|
|
117
107
|
|
|
118
108
|
### Pair only devices you own
|
|
119
109
|
|
|
120
|
-
**A paired node is trusted as you are.**
|
|
121
|
-
authority over this machine that you have: it can create sessions, attach to
|
|
110
|
+
**A paired admin node is trusted as you are.** The `admin` access preset grants
|
|
111
|
+
a node the same authority over this machine that you have: it can create sessions, attach to
|
|
122
112
|
them and type into them as the user running NexusCrew, define engines and cells,
|
|
123
|
-
and read what the fleet exposes.
|
|
113
|
+
and read what the fleet exposes. The `user` and `nexushost` access presets grant
|
|
114
|
+
less authority.
|
|
124
115
|
|
|
125
116
|
Pair your own devices, and only those. Do not accept a pairing invite from
|
|
126
|
-
someone else's installation
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
belongs to somebody else needs per-node authority that can be granted and
|
|
132
|
-
revoked — a capability model, not a setting. It is on the roadmap and it is not
|
|
133
|
-
here yet.
|
|
117
|
+
someone else's installation. Choose the access preset deliberately: `admin`
|
|
118
|
+
grants owner-equivalent authority; `user` and `nexushost` grant less.
|
|
119
|
+
|
|
120
|
+
Federated ASK creation and closure are delivered only to configured `admin`
|
|
121
|
+
peers, hop by hop: each hub applies this rule to its own next peer.
|
|
134
122
|
|
|
135
123
|
Remote access is intentionally carried through SSH or a VPN you control:
|
|
136
124
|
|
package/docs/NOTIFICATIONS.md
CHANGED
|
@@ -119,6 +119,40 @@ browser, keeps the app fully usable, and never changes the other side's push
|
|
|
119
119
|
setup. Turning it back on requires the same button, so a device that was asked
|
|
120
120
|
to stay silent does not re-subscribe itself.
|
|
121
121
|
|
|
122
|
+
## Clearing imported notifications
|
|
123
|
+
|
|
124
|
+
An imported notice can be closed like a local one, for a single notice or for
|
|
125
|
+
the whole visible set of one owner with a single request. The closure is not a
|
|
126
|
+
browser-side hide; the protocol keeps every view of that owner honest:
|
|
127
|
+
|
|
128
|
+
- **The owner records it.** The dismissal travels the authorized routes to the
|
|
129
|
+
owner, is judged by the origin's view, and is answered by one `notify-closed`
|
|
130
|
+
closure frame per cleared notice. Closures enter the owner's feed history, so
|
|
131
|
+
a receiver that was offline recovers them from the backlog; the receiving
|
|
132
|
+
side never turns a closure into a card.
|
|
133
|
+
- **Every receiver empties.** Once the owner has recorded the dismissal he
|
|
134
|
+
stops serving those notices, so no node that holds a view of him keeps
|
|
135
|
+
showing them, whether it was live during the clear or reloads afterwards.
|
|
136
|
+
- **The intent survives when the owner cannot take it.** If the owner is
|
|
137
|
+
unreachable the clear still succeeds: the node records the intent durably
|
|
138
|
+
(a bounded local queue, retries with backoff, one delivery attempt per owner
|
|
139
|
+
at a time) and hands it over when the owner is back. If the owner has no
|
|
140
|
+
notices surface at all the record stays blocked until the pairing changes.
|
|
141
|
+
In both cases the record — not the browser — is what keeps the card down: a
|
|
142
|
+
reload or a restart of the node does not bring it back. If the queue cannot
|
|
143
|
+
write (disk refusal), the intent is still honoured in memory but it cannot
|
|
144
|
+
survive a restart: the answer declares it with `durable: false` and the
|
|
145
|
+
degradation reason, instead of looking like the durable success.
|
|
146
|
+
- **A browser that misses a closure heals at the next read.** The closure
|
|
147
|
+
frame travels live; a browser that never received it (offline, tab asleep)
|
|
148
|
+
catches up at the next fresh feed-state read, which reconciles the panel
|
|
149
|
+
with what the owner still serves. Views that are stale, incomplete or
|
|
150
|
+
flagged for resync never reconcile, so a degraded feed cannot silently
|
|
151
|
+
empty the panel.
|
|
152
|
+
- **"Clear" is the whole visible set of that owner.** It closes every notice
|
|
153
|
+
currently shown for him on this node, in one request inside the owner's
|
|
154
|
+
per-request budget — never one request per card.
|
|
155
|
+
|
|
122
156
|
## Platform notes
|
|
123
157
|
|
|
124
158
|
| Platform | Expected behavior |
|
package/docs/SECURITY.md
CHANGED
|
@@ -86,9 +86,9 @@ their path is inserted into the terminal without automatically pressing Enter.
|
|
|
86
86
|
|
|
87
87
|
## Pairing and sharing
|
|
88
88
|
|
|
89
|
-
**
|
|
89
|
+
**A paired admin node is trusted as you are. Pair only devices you own.**
|
|
90
90
|
|
|
91
|
-
A
|
|
91
|
+
A node with the `admin` access preset can create tmux sessions — including a shell — attach to them over
|
|
92
92
|
the federated WebSocket and write into them as the user running NexusCrew. It
|
|
93
93
|
can define engines and cells, and a custom engine may name an existing
|
|
94
94
|
executable with arguments of its choosing: the trust gate checks the binary's
|
|
@@ -98,9 +98,14 @@ Admission is the exception. Minting a pairing invite is not federated: an invite
|
|
|
98
98
|
belongs to the installation that will host the new node, so it is issued there,
|
|
99
99
|
locally. A paired node cannot admit a third party on your behalf.
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
101
|
+
The `user` preset grants event and file-read access, without administrative
|
|
102
|
+
operations or ASK replies. The `nexushost` preset grants no cell visibility or
|
|
103
|
+
those access rights. Choose the preset on the installation that owns the
|
|
104
|
+
resources. An `admin` peer is trusted as you are; the other presets grant less.
|
|
105
|
+
|
|
106
|
+
Federated ASK creation and closure go only to configured `admin` peers, hop by
|
|
107
|
+
hop. Each hub checks its own next peer before forwarding. This rule does not
|
|
108
|
+
change generic notifications or the relay of ASK replies.
|
|
104
109
|
|
|
105
110
|
### Cell scope
|
|
106
111
|
|
|
@@ -123,13 +128,9 @@ be able to create the cell it was not granted. The terminal attach is gated
|
|
|
123
128
|
with the same predicate, and a tmux session that maps to no cell is outside
|
|
124
129
|
every scope.
|
|
125
130
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
writes into them as the user running NexusCrew. It attenuates reach, not the
|
|
130
|
-
authority held within that reach. A capability model with proof of possession —
|
|
131
|
-
authority granted, attenuated and revoked as a token rather than as
|
|
132
|
-
configuration — remains on the roadmap and is not implemented.
|
|
131
|
+
Cell scope limits the cells a peer can reach; the access preset also limits
|
|
132
|
+
what it can do. Neither is a sandbox for an executable launched with
|
|
133
|
+
administrative authority.
|
|
133
134
|
|
|
134
135
|
So: do not accept a pairing invite from an installation you do not own, and do
|
|
135
136
|
not treat a cell scope as a sandbox for code you do not trust. It is a
|