@mmmbuto/nexuscrew 0.9.16 → 0.9.17
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 +132 -3
- package/docs/ALIBABA_TOKEN_PLAN.md +70 -0
- package/docs/AUDIO_SHARE.md +119 -0
- package/docs/CELL_PANEL.md +156 -0
- package/docs/CONFIGURATION.md +122 -0
- package/docs/FLEET.md +222 -0
- package/docs/INSTALLATION.md +128 -0
- package/docs/LIVE_PROMPT.md +110 -0
- package/docs/MCP.md +151 -0
- package/docs/NODES.md +214 -0
- package/docs/NOTIFICATIONS.md +101 -0
- package/docs/OPERATIONS.md +114 -0
- package/docs/README.md +55 -0
- package/docs/SECURITY.md +185 -0
- package/docs/VL_MICRO_NODES.md +107 -0
- package/docs/img/fleet-deck-desktop.png +0 -0
- package/docs/img/session-mobile.png +0 -0
- package/docs/live-prompt-templates/LIVE_PROMPT.en.md +67 -0
- package/docs/live-prompt-templates/LIVE_PROMPT.es.md +70 -0
- package/docs/live-prompt-templates/LIVE_PROMPT.it.md +67 -0
- package/frontend/dist/assets/{index-CwsGpQwK.js → index-jBYBPXhB.js} +1 -1
- package/frontend/dist/index.html +1 -1
- package/frontend/dist/version.json +1 -1
- package/lib/auth/middleware.js +1 -1
- package/lib/cells/scope-guard.js +2 -2
- package/lib/cli/commands.js +7 -7
- package/lib/cli/fleet-service.js +2 -2
- package/lib/cli/pidfile.js +15 -15
- package/lib/cli/service.js +2 -2
- package/lib/cli/stable-alias.js +1 -1
- package/lib/files/routes.js +2 -2
- package/lib/fleet/builtin.js +6 -6
- package/lib/fleet/cell-exec.js +4 -4
- package/lib/fleet/cell-lease-server.js +17 -17
- package/lib/fleet/definitions.js +5 -5
- package/lib/fleet/launch-broker.js +3 -3
- package/lib/fleet/lease-client.js +1 -1
- package/lib/fleet/managed.js +11 -11
- package/lib/fleet/prompt-delivery.js +1 -1
- package/lib/fleet/runtime.js +3 -3
- package/lib/live-host/bridge.js +3 -3
- package/lib/live-host/routes.js +1 -1
- package/lib/mcp/server.js +7 -8
- package/lib/mcp/tools.js +1 -1
- package/lib/nodes/commands.js +2 -2
- package/lib/nodes/health.js +1 -1
- package/lib/nodes/identity.js +10 -13
- package/lib/nodes/store.js +2 -2
- package/lib/nodes/tunnel-supervisor.js +7 -7
- package/lib/nodes/tunnel.js +10 -11
- package/lib/notify/asks.js +4 -4
- package/lib/notify/persist.js +1 -1
- package/lib/notify/push.js +4 -4
- package/lib/notify/routes.js +12 -12
- package/lib/proxy/node-proxy.js +4 -4
- package/lib/proxy/panel-proxy.js +2 -2
- package/lib/pty/attach.js +1 -1
- package/lib/server.js +3 -3
- package/lib/settings/pairing-coordinator.js +1 -1
- package/lib/settings/routes.js +4 -4
- package/lib/tmux/lifecycle.js +4 -4
- package/lib/tmux/preview.js +1 -1
- package/lib/update/runner.js +9 -9
- package/lib/vl-nodes/broker.js +1 -1
- package/lib/ws/bridge.js +1 -1
- package/package.json +20 -2
- package/frontend/index.html +0 -20
package/lib/proxy/node-proxy.js
CHANGED
|
@@ -42,7 +42,7 @@ const MUTATING = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
|
|
|
42
42
|
// passera' dalla via allowlistata della federazione, mai da questo pass-through
|
|
43
43
|
// generico — che inoltra QUALSIASI path non elencato qui.
|
|
44
44
|
// `/api/route` e `/federation/route` sono qui per una ragione che e' costata un
|
|
45
|
-
//
|
|
45
|
+
// da revisione: l'origine di una richiesta veniva dedotta dal PATH. Su /api/route il
|
|
46
46
|
// gestore assume di parlare col proprietario e non applica gate per-peer; ma un
|
|
47
47
|
// peer poteva farci arrivare quella forma ATTRAVERSO questo stesso pass-through
|
|
48
48
|
// (/node/<A>/api/route/_/panel/<cella>/...), e a quel punto il nodo di
|
|
@@ -182,7 +182,7 @@ function proxyHttp(req, res, node, rest, search, httpRequest) {
|
|
|
182
182
|
// http.request puo' lanciare in modo SINCRONO (es. header value con char
|
|
183
183
|
// invalido dal token del nodo) -> senza try/catch diventa un throw non gestito
|
|
184
184
|
// e Express emette una pagina 500 con lo stack (path interni). Chiudiamo in
|
|
185
|
-
// 502 JSON come gli altri errori upstream, senza esporre nulla. (fix
|
|
185
|
+
// 502 JSON come gli altri errori upstream, senza esporre nulla. (fix da revisione).
|
|
186
186
|
let upstream;
|
|
187
187
|
try {
|
|
188
188
|
upstream = httpRequest(options, (up) => {
|
|
@@ -298,9 +298,9 @@ function handleNodeUpgrade(ctx) {
|
|
|
298
298
|
if (settled) { try { upstream.destroy(); } catch (_) {} return; }
|
|
299
299
|
// buildUpgradeRequest/write possono lanciare (header invalido). Settle DOPO il
|
|
300
300
|
// successo dei write: cosi' il catch -> fail(502) e' OPERATIVO (distrugge entrambi
|
|
301
|
-
// i socket e invia 502) invece di no-op. Prima
|
|
301
|
+
// i socket e invia 502) invece di no-op. Prima della revisione settled veniva messo a
|
|
302
302
|
// true PRIMA dei write: un throw li' rendeva fail() un no-op e lasciava entrambi i
|
|
303
|
-
// socket vivi (leak) senza alcun 502 al client (
|
|
303
|
+
// socket vivi (leak) senza alcun 502 al client (da revisione).
|
|
304
304
|
try {
|
|
305
305
|
upstream.write(buildUpgradeRequest(req.method, parsed.rest, parsed.search, req.headers, node.token, node.localPort));
|
|
306
306
|
if (head && head.length) upstream.write(head);
|
package/lib/proxy/panel-proxy.js
CHANGED
|
@@ -88,7 +88,7 @@ function stripLocalTokenQuery(search) {
|
|
|
88
88
|
// del nostro dominio — inoltrarli significherebbe consegnare al container la
|
|
89
89
|
// sessione del control plane, esattamente cio' che l'Authorization rimossa
|
|
90
90
|
// doveva impedire. E `x-forwarded-*` da un client sono valori che un pannello
|
|
91
|
-
// potrebbe credere veri. Rilievo di
|
|
91
|
+
// potrebbe credere veri. Rilievo di una revisione indipendente.
|
|
92
92
|
function isStrippedRequestHeader(key, value) {
|
|
93
93
|
if (HOP_BY_HOP.has(key)) return true;
|
|
94
94
|
if (key === 'cookie' || key === 'host') return true;
|
|
@@ -194,7 +194,7 @@ async function resolveTarget(resolveCellPanel, cellId) {
|
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
// IL PATH DEL PANNELLO E' `rest`, TAL QUALE. Il contratto
|
|
197
|
+
// IL PATH DEL PANNELLO E' `rest`, TAL QUALE. Il contratto da revisione (CellPanel): il
|
|
198
198
|
// frame carica /api/panel/<cella> + il pathname del panelUrl, e il browser
|
|
199
199
|
// risolve le sotto-risorse RELATIVE rispetto a quell'origine — al proxy
|
|
200
200
|
// arrivano sempre path assoluti del pannello. Ricomporli col basePath del
|
package/lib/pty/attach.js
CHANGED
|
@@ -6,7 +6,7 @@ const { withUtf8Locale } = require('../runtime/env.js');
|
|
|
6
6
|
|
|
7
7
|
// Opens `tmux attach` inside a real PTY, non-destructive for other clients.
|
|
8
8
|
//
|
|
9
|
-
// Size model (emendamento
|
|
9
|
+
// Size model (emendamento di revisione — deck multi-finestra): la sessione usa
|
|
10
10
|
// `window-size latest` (impostato dal bridge). Un client "possiede" la geometria
|
|
11
11
|
// SOLO se NON è `ignore-size`. I tile grid/deck attaccano `ignore-size` (non
|
|
12
12
|
// contendono la geometria da N finestre/N ResizeObserver); l'owner è il tile col
|
package/lib/server.js
CHANGED
|
@@ -93,7 +93,7 @@ function uiBuildVersion(distDir) {
|
|
|
93
93
|
function createServer(opts = {}) {
|
|
94
94
|
const cfg = loadConfig(opts);
|
|
95
95
|
assertLoopback(cfg.bind);
|
|
96
|
-
// Token holder LIVE (
|
|
96
|
+
// Token holder LIVE (da revisione di sicurezza): requireToken/verify leggono tokenStore.get()
|
|
97
97
|
// ad ogni richiesta, cosi' una rotazione via Settings API invalida il VECCHIO token
|
|
98
98
|
// (401) e attiva il NUOVO (200) SENZA restart. Prima il token era catturato una volta
|
|
99
99
|
// allo startup e restava valido fino al restart manuale.
|
|
@@ -136,7 +136,7 @@ function createServer(opts = {}) {
|
|
|
136
136
|
// nei test NON scrivono mai nella home reale. Tutto lazy: vapid.json/asks.json
|
|
137
137
|
// nascono al primo uso, non allo startup.
|
|
138
138
|
const notifyDir = cfg.notifyDir || path.dirname(cfg.tokenPath);
|
|
139
|
-
// READONLY come floor anche dentro il push service (
|
|
139
|
+
// READONLY come floor anche dentro il push service (da revisione): niente generazione
|
|
140
140
|
// VAPID ne' cleanup subscription quando il server e' readonly.
|
|
141
141
|
const bridgeReadonly = () => (cfg.readonlyDefault === true || process.env.NEXUSCREW_READONLY === '1');
|
|
142
142
|
const eventsHub = createEventsHub();
|
|
@@ -585,7 +585,7 @@ function createServer(opts = {}) {
|
|
|
585
585
|
if (!reverseSlotListeners.respond(req, res)) res.status(404).json({ error: 'reverse slot non disponibile' });
|
|
586
586
|
});
|
|
587
587
|
|
|
588
|
-
// Pannello per-cella (
|
|
588
|
+
// Pannello per-cella (da revisione): inoltra il traffico verso il `panelUrl` di UNA cella
|
|
589
589
|
// LOCALE. La destinazione non arriva mai dal chiamante — si risolve dallo stato
|
|
590
590
|
// della cella — e il token di NexusCrew non prosegue verso il pannello, che e'
|
|
591
591
|
// un servizio terzo e non un nodo. Local-only come /api/live-host: il pass-through
|
|
@@ -401,7 +401,7 @@ function createPairHandler(deps) {
|
|
|
401
401
|
});
|
|
402
402
|
}
|
|
403
403
|
|
|
404
|
-
//
|
|
404
|
+
// da revisione: il JOIN ha rivelato la porta pannello del peer — l'informazione
|
|
405
405
|
// che al momento dell'add NON c'era. La riga authorized_keys con DUE
|
|
406
406
|
// destinazioni la emette ADESSO, qui, CHI ha l'informazione: chi ha già
|
|
407
407
|
// incollato la riga di una destinazione è rotto e non lo sa (il server
|
package/lib/settings/routes.js
CHANGED
|
@@ -154,7 +154,7 @@ function settingsRoutes(deps = {}) {
|
|
|
154
154
|
const seams = cfg.settingsSeams || {};
|
|
155
155
|
const localHostname = typeof seams.hostname === 'function' ? seams.hostname : os.hostname;
|
|
156
156
|
// tokenStore/closeSessions iniettati da server.js per la semantica di invalidazione
|
|
157
|
-
// live (
|
|
157
|
+
// live (da revisione di sicurezza). Assenti nei test unitari puri su routes -> la rotazione
|
|
158
158
|
// scrive solo il file (come prima), senza reload in-memory.
|
|
159
159
|
const tokenStore = deps.tokenStore || null;
|
|
160
160
|
const closeSessions = deps.closeSessions || null;
|
|
@@ -164,7 +164,7 @@ function settingsRoutes(deps = {}) {
|
|
|
164
164
|
// configJsonPath() rispetta NEXUSCREW_CONFIG_FILE (stessa risoluzione di
|
|
165
165
|
// loadConfig): settings API e server DEVONO leggere/scrivere lo STESSO file —
|
|
166
166
|
// il fallback home-based divergeva dalla config del server nelle istanze
|
|
167
|
-
// isolate via env (bug trovato in
|
|
167
|
+
// isolate via env (bug trovato in revisione: smoke test che scrivono la config reale).
|
|
168
168
|
const configPath = cfg.configPath || configJsonPath();
|
|
169
169
|
const nodesPath = deps.nodesPath || cfg.nodesPath || nodesStore.defaultNodesPath(home);
|
|
170
170
|
const aliasesPath = deps.aliasesPath || cfg.aliasesPath || nodeAliases.defaultAliasesPath(home);
|
|
@@ -360,7 +360,7 @@ function settingsRoutes(deps = {}) {
|
|
|
360
360
|
|
|
361
361
|
// --- POST /token/rotate — atomico + reload live + chiusura WS; token MAI in risposta
|
|
362
362
|
// Contratto §4b(3): "scrittura atomica del token file + chiusura delle sessioni
|
|
363
|
-
// WS/API attive locali + reload credenziali proxy".
|
|
363
|
+
// WS/API attive locali + reload credenziali proxy". Da revisione: prima questa route
|
|
364
364
|
// scriveva solo il file, e il server teneva il VECCHIO token in memoria -> restava
|
|
365
365
|
// accettato fino al restart manuale. Ora: (1) scrittura atomica, (2) reload live
|
|
366
366
|
// dell'holder in memoria (requireToken/verify vedono il nuovo), (3) chiusura delle
|
|
@@ -548,7 +548,7 @@ function settingsRoutes(deps = {}) {
|
|
|
548
548
|
});
|
|
549
549
|
|
|
550
550
|
// --- POST /nodes/:name/up|down|restart — lifecycle tunnel ------------------
|
|
551
|
-
// GATE READONLY (
|
|
551
|
+
// GATE READONLY (da revisione, contract §4b(6): "restart processi tunnel" e' tra i
|
|
552
552
|
// mutanti della lista chiusa e NEXUSCREW_READONLY blocca TUTTI i mutanti). Prima
|
|
553
553
|
// questi endpoint erano esplicitamente NON gated ("decisione B0") — ma cio'
|
|
554
554
|
// contradiceva il contratto duro §4b(6): up/down/restart mutano processi e vanno
|
package/lib/tmux/lifecycle.js
CHANGED
|
@@ -4,7 +4,7 @@ const path = require('node:path');
|
|
|
4
4
|
const { execFile } = require('node:child_process');
|
|
5
5
|
const { alternateScreenArgs, minimalEnv, tmuxExec } = require('../fleet/launch.js');
|
|
6
6
|
|
|
7
|
-
// Preset allowlistati (
|
|
7
|
+
// Preset allowlistati (da revisione): il client sceglie un NOME, mai un comando.
|
|
8
8
|
// Estendibili da config.json `sessionPresets` (name -> array argv di stringhe).
|
|
9
9
|
const PRESETS = { shell: null, claude: ['claude'], 'codex-vl': ['codex-vl'], pi: ['pi'] };
|
|
10
10
|
|
|
@@ -13,7 +13,7 @@ function validSessionName(name) {
|
|
|
13
13
|
return typeof name === 'string' && NAME_RE.test(name) && !name.startsWith('-');
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
// cwd reale sotto la home reale (
|
|
16
|
+
// cwd reale sotto la home reale (da revisione): realpath su ENTRAMBI, così un
|
|
17
17
|
// symlink dentro home che punta fuori viene rifiutato.
|
|
18
18
|
function resolveCwd(cwd, home) {
|
|
19
19
|
try {
|
|
@@ -25,7 +25,7 @@ function resolveCwd(cwd, home) {
|
|
|
25
25
|
} catch (_) { return null; }
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
// Denylist kill INDIPENDENTE dal registry (
|
|
28
|
+
// Denylist kill INDIPENDENTE dal registry (da revisione): qualunque cloud-* è
|
|
29
29
|
// protetta anche con fleet assente/rotto; in più le tmuxSession del registry.
|
|
30
30
|
function isProtectedSession(name, isCellSession) {
|
|
31
31
|
if (/^cloud-/i.test(String(name))) return true;
|
|
@@ -73,7 +73,7 @@ async function createSession(tmuxBin, { name, cwd, preset }, {
|
|
|
73
73
|
if (typeof ensureProtection === 'function') await ensureProtection();
|
|
74
74
|
await new Promise((resolve, reject) => {
|
|
75
75
|
if (!validSessionName(name)) return reject(httpError(400, 'nome sessione non valido'));
|
|
76
|
-
// Il namespace cloud-* e' delle celle fleet (
|
|
76
|
+
// Il namespace cloud-* e' delle celle fleet (da revisione finale): una generica
|
|
77
77
|
// con quel prefisso occuperebbe il binding per-nome e sarebbe poi 409 al kill.
|
|
78
78
|
if (/^cloud-/i.test(name)) return reject(httpError(409, 'namespace riservato alle celle (cloud-*): usa fleet up'));
|
|
79
79
|
const real = resolveCwd(String(cwd || home), home);
|
package/lib/tmux/preview.js
CHANGED
|
@@ -49,7 +49,7 @@ function analyzeCapture(raw) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
// Sampler con cache per sessione, concorrenza limitata e timeout: la preview è
|
|
52
|
-
// best-effort — errori → null, MAI nel log (
|
|
52
|
+
// best-effort — errori → null, MAI nel log (da revisione).
|
|
53
53
|
function createPreviewSampler(tmuxBin, { ttlMs = 3000, timeoutMs = 1500, maxConcurrent = 4 } = {}) {
|
|
54
54
|
const cache = new Map(); // session -> {at, value}
|
|
55
55
|
let inFlight = 0;
|
package/lib/update/runner.js
CHANGED
|
@@ -10,7 +10,7 @@ const {
|
|
|
10
10
|
stableRuntimeDir,
|
|
11
11
|
} = require('./core.js');
|
|
12
12
|
|
|
13
|
-
//
|
|
13
|
+
// da revisione — rigenerazione delle definizioni di boot dopo l'installazione.
|
|
14
14
|
//
|
|
15
15
|
// L'aggiornamento del pacchetto sposta i path versionati che le unit/plist
|
|
16
16
|
// scrivono LETTERALMENTE (node del Cellar su Homebrew, pacchetto in
|
|
@@ -28,7 +28,7 @@ const {
|
|
|
28
28
|
// Contratto: sana SOLO le definizioni che ESISTONO già (il boot è opt-in:
|
|
29
29
|
// l'update non installa un companion mai chiesto); attivazione differita
|
|
30
30
|
// (activate:false) perché il companion RunAtLoad/oneshot non va eseguito a
|
|
31
|
-
// metà update —
|
|
31
|
+
// metà update — rimedio da revisione: l'attivazione la APPLICA healBootDefinitions
|
|
32
32
|
// nel percorso di update (daemon-reload / bootout+bootstrap), non un restart
|
|
33
33
|
// che non carica le definizioni; un fallimento NON blocca l'aggiornamento
|
|
34
34
|
// (il comportamento senza questo passo era proprio quello) ma viene LOGGATO
|
|
@@ -103,7 +103,7 @@ function regenBootDefinitions(opts = {}) {
|
|
|
103
103
|
out.skipped.push(`${target.component}: nessuna definizione installata, nulla da sanare`);
|
|
104
104
|
continue;
|
|
105
105
|
}
|
|
106
|
-
//
|
|
106
|
+
// rimedio da revisione, difetto 3: symlink e directory al posto del target
|
|
107
107
|
// erano già saltati, ma un FILE REGOLARE DI TERZI veniva sovrascritto. Le
|
|
108
108
|
// definizioni che generiamo portano tutte il nome del progetto nell'header
|
|
109
109
|
// (systemd: «# NexusCrew service», plist: Label com.mmmbuto.nexuscrew):
|
|
@@ -111,7 +111,7 @@ function regenBootDefinitions(opts = {}) {
|
|
|
111
111
|
// — lo skip è dichiarato, non silenzioso. Un file illeggibile non blocca
|
|
112
112
|
// la sanazione (si presume nostro: il caso terzi è il contenuto leggibile
|
|
113
113
|
// che dichiara altro).
|
|
114
|
-
//
|
|
114
|
+
// da revisione: la proprieta' si riconosce da un'ancora STRUTTURALE del
|
|
115
115
|
// nostro generatore (isOurService/isOurFleetService), non dalla parola
|
|
116
116
|
// «nexuscrew» presente nel file: un unit di terzi che ci nomina in un
|
|
117
117
|
// commento veniva sovrascritto. E cio' che NON si riesce a leggere non si
|
|
@@ -147,7 +147,7 @@ function regenBootDefinitions(opts = {}) {
|
|
|
147
147
|
return out;
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
//
|
|
150
|
+
// rimedio da revisione, difetto 2: l'attivazione differita dichiarata dalla
|
|
151
151
|
// regen era una promessa FALSA in silenzio. `restart` fa `systemctl --user
|
|
152
152
|
// restart` SENZA daemon-reload (systemd riavvia con la definizione VECCHIA
|
|
153
153
|
// in memoria) e `launchctl kickstart` riusa la definizione già caricata; col
|
|
@@ -365,9 +365,9 @@ async function runUpdate(opts = {}) {
|
|
|
365
365
|
installedNew = true;
|
|
366
366
|
await preflightImpl({ version, home });
|
|
367
367
|
writeState(statusPath, { ...readState(statusPath), phase: 'restarting', updaterPid: process.pid, lastError: '' });
|
|
368
|
-
//
|
|
368
|
+
// da revisione: sana le definizioni di boot PRIMA del riavvio — è il passo che
|
|
369
369
|
// manca al percorso di upgrade e che lasciava la companion puntata a un
|
|
370
|
-
// binario morto (exit 78, silenzio).
|
|
370
|
+
// binario morto (exit 78, silenzio). rimedio da revisione: la sanazione ora
|
|
371
371
|
// APPLICA anche l'attivazione differita (healBootDefinitions) — il
|
|
372
372
|
// restart da solo non caricava le definizioni riscritte. Best-effort
|
|
373
373
|
// DICHIARATO: un errore qui non blocca l'aggiornamento, viene loggato e
|
|
@@ -391,9 +391,9 @@ async function runUpdate(opts = {}) {
|
|
|
391
391
|
});
|
|
392
392
|
if (String(readInstalledVersion() || '') !== previousVersion) throw new Error(`rollback verify: attesa ${previousVersion}`);
|
|
393
393
|
await preflightImpl({ version: previousVersion, home, rollback: true });
|
|
394
|
-
//
|
|
394
|
+
// da revisione: il rollback riparte dalle stesse definizioni sane — il
|
|
395
395
|
// downgrade reinstalla il pacchetto nel prefix attuale e i path
|
|
396
|
-
// vivi valgono anche per la versione precedente.
|
|
396
|
+
// vivi valgono anche per la versione precedente. rimedio da revisione:
|
|
397
397
|
// anche qui sanazione+attivazione (heal), non la sola regen.
|
|
398
398
|
(opts.healBootImpl || healBootDefinitions)({
|
|
399
399
|
home, running: wasRunning, execImpl, ...(opts.regenSeams || {}),
|
package/lib/vl-nodes/broker.js
CHANGED
|
@@ -118,7 +118,7 @@ function sanitizeEvents(raw) {
|
|
|
118
118
|
return { events, dropped };
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
// La sessione VL dichiarata dal nodo (sidebar:
|
|
121
|
+
// La sessione VL dichiarata dal nodo (sidebar: «<device> · <n> sessioni»). Solo
|
|
122
122
|
// attach + label del profilo, mai contenuto: qualunque campo extra viene
|
|
123
123
|
// potato, non troncato — stessa disciplina della whitelist eventi. Assente o
|
|
124
124
|
// invalida -> null: un binario piu' vecchio non dichiara sessioni che non ha
|
package/lib/ws/bridge.js
CHANGED
|
@@ -243,7 +243,7 @@ function bindWs(ws, deps) {
|
|
|
243
243
|
// e' READONLY nessun client puo' declassarlo (msg.readonly:false non deve
|
|
244
244
|
// vincere). Il client puo' solo AGGIUNGERE restrizione (attach read-only
|
|
245
245
|
// su un server read-write). Contratto design §4b(6): READONLY blocca anche
|
|
246
|
-
// le scritture PTY. (fix
|
|
246
|
+
// le scritture PTY. (fix da revisione finale: prima il ?? faceva vincere il client.)
|
|
247
247
|
readonly: defaults.readonlyDefault === true || !!msg.readonly,
|
|
248
248
|
takeSize,
|
|
249
249
|
cols: clamp(msg.cols, 20, 300, 80),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmmbuto/nexuscrew",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.17",
|
|
4
4
|
"description": "Faithful browser tmux client — attach to live sessions over a real PTY, localhost-only, mobile-easy",
|
|
5
5
|
"main": "lib/server.js",
|
|
6
6
|
"bin": {
|
|
@@ -11,8 +11,26 @@
|
|
|
11
11
|
"lib/",
|
|
12
12
|
"skills/",
|
|
13
13
|
"frontend/dist/",
|
|
14
|
-
"frontend/index.html",
|
|
15
14
|
"CHANGELOG.md",
|
|
15
|
+
"docs/ALIBABA_TOKEN_PLAN.md",
|
|
16
|
+
"docs/AUDIO_SHARE.md",
|
|
17
|
+
"docs/CELL_PANEL.md",
|
|
18
|
+
"docs/CONFIGURATION.md",
|
|
19
|
+
"docs/FLEET.md",
|
|
20
|
+
"docs/INSTALLATION.md",
|
|
21
|
+
"docs/LIVE_PROMPT.md",
|
|
22
|
+
"docs/live-prompt-templates/LIVE_PROMPT.en.md",
|
|
23
|
+
"docs/live-prompt-templates/LIVE_PROMPT.es.md",
|
|
24
|
+
"docs/live-prompt-templates/LIVE_PROMPT.it.md",
|
|
25
|
+
"docs/img/fleet-deck-desktop.png",
|
|
26
|
+
"docs/img/session-mobile.png",
|
|
27
|
+
"docs/MCP.md",
|
|
28
|
+
"docs/NODES.md",
|
|
29
|
+
"docs/NOTIFICATIONS.md",
|
|
30
|
+
"docs/OPERATIONS.md",
|
|
31
|
+
"docs/README.md",
|
|
32
|
+
"docs/SECURITY.md",
|
|
33
|
+
"docs/VL_MICRO_NODES.md",
|
|
16
34
|
"MCP_COMPANIONS.md",
|
|
17
35
|
"mcp-companions.json",
|
|
18
36
|
"LICENSE",
|
package/frontend/index.html
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover, interactive-widget=resizes-content" />
|
|
6
|
-
<meta name="theme-color" content="#0d1117" />
|
|
7
|
-
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
8
|
-
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
9
|
-
<meta name="mobile-web-app-capable" content="yes" />
|
|
10
|
-
<meta name="application-name" content="NexusCrew" />
|
|
11
|
-
<meta name="apple-mobile-web-app-title" content="NexusCrew" />
|
|
12
|
-
<link rel="manifest" href="/manifest.json" />
|
|
13
|
-
<title>NexusCrew</title>
|
|
14
|
-
</head>
|
|
15
|
-
<body>
|
|
16
|
-
<div id="root"></div>
|
|
17
|
-
<script>if('serviceWorker' in navigator) navigator.serviceWorker.register('/sw.js');</script>
|
|
18
|
-
<script type="module" src="/src/main.jsx"></script>
|
|
19
|
-
</body>
|
|
20
|
-
</html>
|