@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.
Files changed (67) hide show
  1. package/CHANGELOG.md +132 -3
  2. package/docs/ALIBABA_TOKEN_PLAN.md +70 -0
  3. package/docs/AUDIO_SHARE.md +119 -0
  4. package/docs/CELL_PANEL.md +156 -0
  5. package/docs/CONFIGURATION.md +122 -0
  6. package/docs/FLEET.md +222 -0
  7. package/docs/INSTALLATION.md +128 -0
  8. package/docs/LIVE_PROMPT.md +110 -0
  9. package/docs/MCP.md +151 -0
  10. package/docs/NODES.md +214 -0
  11. package/docs/NOTIFICATIONS.md +101 -0
  12. package/docs/OPERATIONS.md +114 -0
  13. package/docs/README.md +55 -0
  14. package/docs/SECURITY.md +185 -0
  15. package/docs/VL_MICRO_NODES.md +107 -0
  16. package/docs/img/fleet-deck-desktop.png +0 -0
  17. package/docs/img/session-mobile.png +0 -0
  18. package/docs/live-prompt-templates/LIVE_PROMPT.en.md +67 -0
  19. package/docs/live-prompt-templates/LIVE_PROMPT.es.md +70 -0
  20. package/docs/live-prompt-templates/LIVE_PROMPT.it.md +67 -0
  21. package/frontend/dist/assets/{index-CwsGpQwK.js → index-jBYBPXhB.js} +1 -1
  22. package/frontend/dist/index.html +1 -1
  23. package/frontend/dist/version.json +1 -1
  24. package/lib/auth/middleware.js +1 -1
  25. package/lib/cells/scope-guard.js +2 -2
  26. package/lib/cli/commands.js +7 -7
  27. package/lib/cli/fleet-service.js +2 -2
  28. package/lib/cli/pidfile.js +15 -15
  29. package/lib/cli/service.js +2 -2
  30. package/lib/cli/stable-alias.js +1 -1
  31. package/lib/files/routes.js +2 -2
  32. package/lib/fleet/builtin.js +6 -6
  33. package/lib/fleet/cell-exec.js +4 -4
  34. package/lib/fleet/cell-lease-server.js +17 -17
  35. package/lib/fleet/definitions.js +5 -5
  36. package/lib/fleet/launch-broker.js +3 -3
  37. package/lib/fleet/lease-client.js +1 -1
  38. package/lib/fleet/managed.js +11 -11
  39. package/lib/fleet/prompt-delivery.js +1 -1
  40. package/lib/fleet/runtime.js +3 -3
  41. package/lib/live-host/bridge.js +3 -3
  42. package/lib/live-host/routes.js +1 -1
  43. package/lib/mcp/server.js +7 -8
  44. package/lib/mcp/tools.js +1 -1
  45. package/lib/nodes/commands.js +2 -2
  46. package/lib/nodes/health.js +1 -1
  47. package/lib/nodes/identity.js +10 -13
  48. package/lib/nodes/store.js +2 -2
  49. package/lib/nodes/tunnel-supervisor.js +7 -7
  50. package/lib/nodes/tunnel.js +10 -11
  51. package/lib/notify/asks.js +4 -4
  52. package/lib/notify/persist.js +1 -1
  53. package/lib/notify/push.js +4 -4
  54. package/lib/notify/routes.js +12 -12
  55. package/lib/proxy/node-proxy.js +4 -4
  56. package/lib/proxy/panel-proxy.js +2 -2
  57. package/lib/pty/attach.js +1 -1
  58. package/lib/server.js +3 -3
  59. package/lib/settings/pairing-coordinator.js +1 -1
  60. package/lib/settings/routes.js +4 -4
  61. package/lib/tmux/lifecycle.js +4 -4
  62. package/lib/tmux/preview.js +1 -1
  63. package/lib/update/runner.js +9 -9
  64. package/lib/vl-nodes/broker.js +1 -1
  65. package/lib/ws/bridge.js +1 -1
  66. package/package.json +20 -2
  67. package/frontend/index.html +0 -20
@@ -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
- // audit: l'origine di una richiesta veniva dedotta dal PATH. Su /api/route il
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 audit).
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 dell'audit settled veniva messo a
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 (audit F5).
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);
@@ -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 un audit indipendente.
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 D8 (CellPanel): il
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 post-audit §5b — deck multi-finestra): la sessione usa
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 (audit F7 / §4b(3)): requireToken/verify leggono tokenStore.get()
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 (F3): niente generazione
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 (D8): inoltra il traffico verso il `panelUrl` di UNA 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
- // R19: il JOIN ha rivelato la porta pannello del peer — l'informazione
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
@@ -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 (audit F7 / §4b(3)). Assenti nei test unitari puri su routes -> la rotazione
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 audit: smoke test che scrivono la config reale).
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". Audit F7: prima questa route
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 (audit F6, contract §4b(6): "restart processi tunnel" e' tra i
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
@@ -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 (audit F1): il client sceglie un NOME, mai un comando.
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 (audit F1): realpath su ENTRAMBI, così un
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 (audit F2): qualunque cloud-* è
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 (audit finale #1): una generica
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);
@@ -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 (audit F7).
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;
@@ -10,7 +10,7 @@ const {
10
10
  stableRuntimeDir,
11
11
  } = require('./core.js');
12
12
 
13
- // R28 — rigenerazione delle definizioni di boot dopo l'installazione.
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 — R28-rimedio: l'attivazione la APPLICA healBootDefinitions
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
- // R28-rimedio, difetto 3 (audit): symlink e directory al posto del target
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
- // R28 (audit rev2): la proprieta' si riconosce da un'ancora STRUTTURALE del
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
- // R28-rimedio, difetto 2 (audit): l'attivazione differita dichiarata dalla
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
- // R28: sana le definizioni di boot PRIMA del riavvio — è il passo che
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). R28-rimedio: la sanazione ora
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
- // R28: il rollback riparte dalle stesse definizioni sane — il
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. R28-rimedio:
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 || {}),
@@ -118,7 +118,7 @@ function sanitizeEvents(raw) {
118
118
  return { events, dropped };
119
119
  }
120
120
 
121
- // La sessione VL dichiarata dal nodo (sidebar: «N900 · 1 sessione»). Solo
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 audit finale: prima il ?? faceva vincere il client.)
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.16",
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",
@@ -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>