@mmmbuto/nexuscli 0.5.0
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/LICENSE +21 -0
- package/README.md +172 -0
- package/bin/nexuscli.js +117 -0
- package/frontend/dist/apple-touch-icon.png +0 -0
- package/frontend/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/frontend/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/frontend/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/frontend/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/frontend/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/frontend/dist/assets/index-Bn_l1e6e.css +1 -0
- package/frontend/dist/assets/index-CikJbUR5.js +8617 -0
- package/frontend/dist/browserconfig.xml +12 -0
- package/frontend/dist/favicon-16x16.png +0 -0
- package/frontend/dist/favicon-32x32.png +0 -0
- package/frontend/dist/favicon-48x48.png +0 -0
- package/frontend/dist/favicon.ico +0 -0
- package/frontend/dist/icon-192.png +0 -0
- package/frontend/dist/icon-512.png +0 -0
- package/frontend/dist/icon-maskable-192.png +0 -0
- package/frontend/dist/icon-maskable-512.png +0 -0
- package/frontend/dist/index.html +79 -0
- package/frontend/dist/manifest.json +75 -0
- package/frontend/dist/sw.js +122 -0
- package/frontend/package.json +28 -0
- package/lib/cli/api.js +156 -0
- package/lib/cli/boot.js +172 -0
- package/lib/cli/config.js +185 -0
- package/lib/cli/engines.js +257 -0
- package/lib/cli/init.js +660 -0
- package/lib/cli/logs.js +72 -0
- package/lib/cli/start.js +220 -0
- package/lib/cli/status.js +187 -0
- package/lib/cli/stop.js +64 -0
- package/lib/cli/uninstall.js +194 -0
- package/lib/cli/users.js +295 -0
- package/lib/cli/workspaces.js +337 -0
- package/lib/config/manager.js +233 -0
- package/lib/server/.env.example +20 -0
- package/lib/server/db/adapter.js +314 -0
- package/lib/server/db/drivers/better-sqlite3.js +38 -0
- package/lib/server/db/drivers/sql-js.js +75 -0
- package/lib/server/db/migrate.js +174 -0
- package/lib/server/db/migrations/001_ultra_light_schema.sql +96 -0
- package/lib/server/db/migrations/002_session_conversation_mapping.sql +19 -0
- package/lib/server/db/migrations/003_message_engine_tracking.sql +18 -0
- package/lib/server/db/migrations/004_performance_indexes.sql +16 -0
- package/lib/server/db.js +2 -0
- package/lib/server/lib/cli-wrapper.js +164 -0
- package/lib/server/lib/output-parser.js +132 -0
- package/lib/server/lib/pty-adapter.js +57 -0
- package/lib/server/middleware/auth.js +103 -0
- package/lib/server/models/Conversation.js +259 -0
- package/lib/server/models/Message.js +228 -0
- package/lib/server/models/User.js +115 -0
- package/lib/server/package-lock.json +5895 -0
- package/lib/server/routes/auth.js +168 -0
- package/lib/server/routes/chat.js +206 -0
- package/lib/server/routes/codex.js +205 -0
- package/lib/server/routes/conversations.js +224 -0
- package/lib/server/routes/gemini.js +228 -0
- package/lib/server/routes/jobs.js +317 -0
- package/lib/server/routes/messages.js +60 -0
- package/lib/server/routes/models.js +198 -0
- package/lib/server/routes/sessions.js +285 -0
- package/lib/server/routes/upload.js +134 -0
- package/lib/server/routes/wake-lock.js +95 -0
- package/lib/server/routes/workspace.js +80 -0
- package/lib/server/routes/workspaces.js +142 -0
- package/lib/server/scripts/cleanup-ghost-sessions.js +71 -0
- package/lib/server/scripts/seed-users.js +37 -0
- package/lib/server/scripts/test-history-access.js +50 -0
- package/lib/server/server.js +227 -0
- package/lib/server/services/cache.js +85 -0
- package/lib/server/services/claude-wrapper.js +312 -0
- package/lib/server/services/cli-loader.js +384 -0
- package/lib/server/services/codex-output-parser.js +277 -0
- package/lib/server/services/codex-wrapper.js +224 -0
- package/lib/server/services/context-bridge.js +289 -0
- package/lib/server/services/gemini-output-parser.js +398 -0
- package/lib/server/services/gemini-wrapper.js +249 -0
- package/lib/server/services/history-sync.js +407 -0
- package/lib/server/services/output-parser.js +415 -0
- package/lib/server/services/session-manager.js +465 -0
- package/lib/server/services/summary-generator.js +259 -0
- package/lib/server/services/workspace-manager.js +516 -0
- package/lib/server/tests/history-sync.test.js +90 -0
- package/lib/server/tests/integration-session-sync.test.js +151 -0
- package/lib/server/tests/integration.test.js +76 -0
- package/lib/server/tests/performance.test.js +118 -0
- package/lib/server/tests/services.test.js +160 -0
- package/lib/setup/postinstall.js +216 -0
- package/lib/utils/paths.js +107 -0
- package/lib/utils/termux.js +145 -0
- package/package.json +82 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<browserconfig>
|
|
3
|
+
<msapplication>
|
|
4
|
+
<tile>
|
|
5
|
+
<square70x70logo src="/icon-192.png"/>
|
|
6
|
+
<square150x150logo src="/icon-192.png"/>
|
|
7
|
+
<square310x310logo src="/icon-512.png"/>
|
|
8
|
+
<wide310x150logo src="/icon-512.png"/>
|
|
9
|
+
<TileColor>#00ff9f</TileColor>
|
|
10
|
+
</tile>
|
|
11
|
+
</msapplication>
|
|
12
|
+
</browserconfig>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,79 @@
|
|
|
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, viewport-fit=cover" />
|
|
6
|
+
|
|
7
|
+
<!-- Primary Meta Tags -->
|
|
8
|
+
<title>NexusCLI - AI Assistant Interface</title>
|
|
9
|
+
<meta name="title" content="NexusCLI - AI Assistant Interface" />
|
|
10
|
+
<meta name="description" content="Multi-CLI AI Assistant Interface - Claude Code, Codex, and more. Your command center for AI interactions." />
|
|
11
|
+
<meta name="keywords" content="AI, CLI, Claude, Assistant, NexusCLI, Terminal, Interface" />
|
|
12
|
+
<meta name="author" content="NexusCLI Team" />
|
|
13
|
+
|
|
14
|
+
<!-- Theme Color -->
|
|
15
|
+
<meta name="theme-color" content="#1a1a1a" />
|
|
16
|
+
<meta name="msapplication-TileColor" content="#1a1a1a" />
|
|
17
|
+
<meta name="msapplication-navbutton-color" content="#1a1a1a" />
|
|
18
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
|
19
|
+
|
|
20
|
+
<!-- PWA Meta Tags -->
|
|
21
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
22
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
23
|
+
<meta name="apple-mobile-web-app-title" content="NexusCLI" />
|
|
24
|
+
<meta name="application-name" content="NexusCLI" />
|
|
25
|
+
|
|
26
|
+
<!-- Favicon -->
|
|
27
|
+
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
|
28
|
+
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
|
29
|
+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
|
30
|
+
<link rel="icon" type="image/png" sizes="48x48" href="/favicon-48x48.png" />
|
|
31
|
+
|
|
32
|
+
<!-- Apple Touch Icon -->
|
|
33
|
+
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
34
|
+
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
|
35
|
+
|
|
36
|
+
<!-- Android Chrome -->
|
|
37
|
+
<link rel="icon" type="image/png" sizes="192x192" href="/icon-192.png" />
|
|
38
|
+
<link rel="icon" type="image/png" sizes="512x512" href="/icon-512.png" />
|
|
39
|
+
|
|
40
|
+
<!-- Web App Manifest -->
|
|
41
|
+
<link rel="manifest" href="/manifest.json" />
|
|
42
|
+
|
|
43
|
+
<!-- Microsoft Tiles -->
|
|
44
|
+
<meta name="msapplication-config" content="/browserconfig.xml" />
|
|
45
|
+
|
|
46
|
+
<!-- Open Graph / Facebook -->
|
|
47
|
+
<meta property="og:type" content="website" />
|
|
48
|
+
<meta property="og:url" content="https://cli.wellanet.dev/" />
|
|
49
|
+
<meta property="og:title" content="NexusCLI - AI Assistant Interface" />
|
|
50
|
+
<meta property="og:description" content="Multi-CLI AI Assistant Interface - Your command center for AI interactions." />
|
|
51
|
+
<meta property="og:image" content="https://cli.wellanet.dev/icon-512.png" />
|
|
52
|
+
|
|
53
|
+
<!-- Twitter -->
|
|
54
|
+
<meta property="twitter:card" content="summary_large_image" />
|
|
55
|
+
<meta property="twitter:url" content="https://cli.wellanet.dev/" />
|
|
56
|
+
<meta property="twitter:title" content="NexusCLI - AI Assistant Interface" />
|
|
57
|
+
<meta property="twitter:description" content="Multi-CLI AI Assistant Interface - Your command center for AI interactions." />
|
|
58
|
+
<meta property="twitter:image" content="https://cli.wellanet.dev/icon-512.png" />
|
|
59
|
+
|
|
60
|
+
<!-- Prevent Scaling on iOS -->
|
|
61
|
+
<meta name="format-detection" content="telephone=no" />
|
|
62
|
+
<script type="module" crossorigin src="/assets/index-CikJbUR5.js"></script>
|
|
63
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Bn_l1e6e.css">
|
|
64
|
+
</head>
|
|
65
|
+
<body>
|
|
66
|
+
<div id="root"></div>
|
|
67
|
+
|
|
68
|
+
<!-- Service Worker Registration -->
|
|
69
|
+
<script>
|
|
70
|
+
if ('serviceWorker' in navigator) {
|
|
71
|
+
window.addEventListener('load', () => {
|
|
72
|
+
navigator.serviceWorker.register('/sw.js')
|
|
73
|
+
.then(registration => console.log('SW registered:', registration.scope))
|
|
74
|
+
.catch(err => console.log('SW registration failed:', err));
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
78
|
+
</body>
|
|
79
|
+
</html>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "NexusCLI - AI Assistant Interface",
|
|
3
|
+
"short_name": "NexusCLI",
|
|
4
|
+
"description": "Multi-CLI AI Assistant Interface - Claude Code, Codex, and more",
|
|
5
|
+
"start_url": "/",
|
|
6
|
+
"display": "standalone",
|
|
7
|
+
"background_color": "#1a1a1a",
|
|
8
|
+
"theme_color": "#00ff9f",
|
|
9
|
+
"orientation": "portrait-primary",
|
|
10
|
+
"icons": [
|
|
11
|
+
{
|
|
12
|
+
"src": "/favicon-16x16.png",
|
|
13
|
+
"sizes": "16x16",
|
|
14
|
+
"type": "image/png"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"src": "/favicon-32x32.png",
|
|
18
|
+
"sizes": "32x32",
|
|
19
|
+
"type": "image/png"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"src": "/favicon-48x48.png",
|
|
23
|
+
"sizes": "48x48",
|
|
24
|
+
"type": "image/png"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"src": "/apple-touch-icon.png",
|
|
28
|
+
"sizes": "180x180",
|
|
29
|
+
"type": "image/png",
|
|
30
|
+
"purpose": "any"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"src": "/icon-192.png",
|
|
34
|
+
"sizes": "192x192",
|
|
35
|
+
"type": "image/png",
|
|
36
|
+
"purpose": "any"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"src": "/icon-512.png",
|
|
40
|
+
"sizes": "512x512",
|
|
41
|
+
"type": "image/png",
|
|
42
|
+
"purpose": "any"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"src": "/icon-maskable-192.png",
|
|
46
|
+
"sizes": "192x192",
|
|
47
|
+
"type": "image/png",
|
|
48
|
+
"purpose": "maskable"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"src": "/icon-maskable-512.png",
|
|
52
|
+
"sizes": "512x512",
|
|
53
|
+
"type": "image/png",
|
|
54
|
+
"purpose": "maskable"
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"categories": ["productivity", "utilities", "development"],
|
|
58
|
+
"screenshots": [],
|
|
59
|
+
"shortcuts": [
|
|
60
|
+
{
|
|
61
|
+
"name": "New Chat",
|
|
62
|
+
"short_name": "New Chat",
|
|
63
|
+
"description": "Start a new AI conversation",
|
|
64
|
+
"url": "/?action=new",
|
|
65
|
+
"icons": [
|
|
66
|
+
{
|
|
67
|
+
"src": "/icon-192.png",
|
|
68
|
+
"sizes": "192x192",
|
|
69
|
+
"type": "image/png"
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"prefer_related_applications": false
|
|
75
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// NexusCLI Service Worker
|
|
2
|
+
const CACHE_VERSION = 'nexuscli-v1';
|
|
3
|
+
const STATIC_CACHE = `${CACHE_VERSION}-static`;
|
|
4
|
+
const DYNAMIC_CACHE = `${CACHE_VERSION}-dynamic`;
|
|
5
|
+
|
|
6
|
+
// Assets to cache on install
|
|
7
|
+
const STATIC_ASSETS = [
|
|
8
|
+
'/',
|
|
9
|
+
'/index.html',
|
|
10
|
+
'/manifest.json',
|
|
11
|
+
'/favicon.ico',
|
|
12
|
+
'/icon-192.png',
|
|
13
|
+
'/icon-512.png',
|
|
14
|
+
'/apple-touch-icon.png'
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
// Install event - cache static assets
|
|
18
|
+
self.addEventListener('install', (event) => {
|
|
19
|
+
console.log('[SW] Installing service worker...');
|
|
20
|
+
event.waitUntil(
|
|
21
|
+
caches.open(STATIC_CACHE)
|
|
22
|
+
.then(cache => {
|
|
23
|
+
console.log('[SW] Caching static assets');
|
|
24
|
+
return cache.addAll(STATIC_ASSETS);
|
|
25
|
+
})
|
|
26
|
+
.then(() => self.skipWaiting())
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
// Activate event - cleanup old caches
|
|
31
|
+
self.addEventListener('activate', (event) => {
|
|
32
|
+
console.log('[SW] Activating service worker...');
|
|
33
|
+
event.waitUntil(
|
|
34
|
+
caches.keys().then(cacheNames => {
|
|
35
|
+
return Promise.all(
|
|
36
|
+
cacheNames
|
|
37
|
+
.filter(name => name.startsWith('nexuscli-') && name !== STATIC_CACHE && name !== DYNAMIC_CACHE)
|
|
38
|
+
.map(name => {
|
|
39
|
+
console.log('[SW] Deleting old cache:', name);
|
|
40
|
+
return caches.delete(name);
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
}).then(() => self.clients.claim())
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Fetch event - serve from cache, fallback to network
|
|
48
|
+
self.addEventListener('fetch', (event) => {
|
|
49
|
+
const { request } = event;
|
|
50
|
+
const url = new URL(request.url);
|
|
51
|
+
|
|
52
|
+
// Skip non-GET requests
|
|
53
|
+
if (request.method !== 'GET') {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// API requests - network first, cache fallback
|
|
58
|
+
if (url.pathname.startsWith('/api/')) {
|
|
59
|
+
event.respondWith(
|
|
60
|
+
fetch(request)
|
|
61
|
+
.then(response => {
|
|
62
|
+
// Clone response to store in cache
|
|
63
|
+
const responseClone = response.clone();
|
|
64
|
+
caches.open(DYNAMIC_CACHE).then(cache => {
|
|
65
|
+
cache.put(request, responseClone);
|
|
66
|
+
});
|
|
67
|
+
return response;
|
|
68
|
+
})
|
|
69
|
+
.catch(() => {
|
|
70
|
+
// Fallback to cache if network fails
|
|
71
|
+
return caches.match(request);
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Static assets - cache first, network fallback
|
|
78
|
+
event.respondWith(
|
|
79
|
+
caches.match(request)
|
|
80
|
+
.then(cached => {
|
|
81
|
+
if (cached) {
|
|
82
|
+
console.log('[SW] Serving from cache:', request.url);
|
|
83
|
+
return cached;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return fetch(request)
|
|
87
|
+
.then(response => {
|
|
88
|
+
// Don't cache non-successful responses
|
|
89
|
+
if (!response || response.status !== 200 || response.type === 'error') {
|
|
90
|
+
return response;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Clone response to store in cache
|
|
94
|
+
const responseClone = response.clone();
|
|
95
|
+
caches.open(DYNAMIC_CACHE).then(cache => {
|
|
96
|
+
cache.put(request, responseClone);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return response;
|
|
100
|
+
});
|
|
101
|
+
})
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Handle messages from clients
|
|
106
|
+
self.addEventListener('message', (event) => {
|
|
107
|
+
if (event.data && event.data.type === 'SKIP_WAITING') {
|
|
108
|
+
self.skipWaiting();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Background sync for offline support (if needed)
|
|
113
|
+
self.addEventListener('sync', (event) => {
|
|
114
|
+
if (event.tag === 'sync-messages') {
|
|
115
|
+
event.waitUntil(syncMessages());
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
async function syncMessages() {
|
|
120
|
+
// Implement message sync logic here if needed
|
|
121
|
+
console.log('[SW] Syncing messages...');
|
|
122
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nexuscli-frontend",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "NexusCLI Frontend - Control Plane UI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"i18next": "^23.11.5",
|
|
13
|
+
"i18next-browser-languagedetector": "^7.1.0",
|
|
14
|
+
"lucide-react": "^0.554.0",
|
|
15
|
+
"react": "^18.2.0",
|
|
16
|
+
"react-dom": "^18.2.0",
|
|
17
|
+
"react-i18next": "^13.5.0",
|
|
18
|
+
"react-markdown": "^10.1.0",
|
|
19
|
+
"rehype-highlight": "^7.0.2",
|
|
20
|
+
"rehype-katex": "^7.0.1",
|
|
21
|
+
"remark-gfm": "^4.0.1",
|
|
22
|
+
"remark-math": "^6.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@vitejs/plugin-react": "^4.2.1",
|
|
26
|
+
"vite": "^5.0.8"
|
|
27
|
+
}
|
|
28
|
+
}
|
package/lib/cli/api.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nexuscli api - Manage API keys for AI providers
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* nexuscli api list - List configured providers
|
|
6
|
+
* nexuscli api set <provider> <key> - Set API key
|
|
7
|
+
* nexuscli api delete <provider> - Delete API key
|
|
8
|
+
*
|
|
9
|
+
* Providers:
|
|
10
|
+
* - deepseek (DeepSeek Chat/Reasoner)
|
|
11
|
+
* - openai (GPT models)
|
|
12
|
+
* - anthropic (Claude models - usually via OAuth)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { initDb, setApiKey, deleteApiKey, listApiKeyProviders, getApiKey } = require('../server/db');
|
|
16
|
+
|
|
17
|
+
const SUPPORTED_PROVIDERS = {
|
|
18
|
+
deepseek: {
|
|
19
|
+
name: 'DeepSeek',
|
|
20
|
+
description: 'DeepSeek Chat & Reasoner models',
|
|
21
|
+
keyFormat: 'sk-*',
|
|
22
|
+
url: 'https://platform.deepseek.com/api_keys'
|
|
23
|
+
},
|
|
24
|
+
openai: {
|
|
25
|
+
name: 'OpenAI',
|
|
26
|
+
description: 'GPT-4, STT/TTS (Whisper)',
|
|
27
|
+
keyFormat: 'sk-*',
|
|
28
|
+
url: 'https://platform.openai.com/api-keys'
|
|
29
|
+
},
|
|
30
|
+
openrouter: {
|
|
31
|
+
name: 'OpenRouter',
|
|
32
|
+
description: 'Multi-provider gateway',
|
|
33
|
+
keyFormat: 'sk-or-*',
|
|
34
|
+
url: 'https://openrouter.ai/keys'
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
async function apiCommand(action, provider, key) {
|
|
39
|
+
// Initialize database
|
|
40
|
+
await initDb({ skipMigrationCheck: true });
|
|
41
|
+
|
|
42
|
+
if (!action || action === 'list') {
|
|
43
|
+
// List configured providers
|
|
44
|
+
const providers = listApiKeyProviders();
|
|
45
|
+
|
|
46
|
+
console.log('\n🔑 Configured API Keys:\n');
|
|
47
|
+
|
|
48
|
+
if (providers.length === 0) {
|
|
49
|
+
console.log(' No API keys configured.\n');
|
|
50
|
+
console.log(' To add a key:');
|
|
51
|
+
console.log(' nexuscli api set deepseek sk-your-api-key\n');
|
|
52
|
+
} else {
|
|
53
|
+
providers.forEach(p => {
|
|
54
|
+
const info = SUPPORTED_PROVIDERS[p.provider] || { name: p.provider };
|
|
55
|
+
const date = new Date(p.updated_at).toLocaleDateString();
|
|
56
|
+
console.log(` ✅ ${info.name || p.provider} (${p.provider})`);
|
|
57
|
+
console.log(` Updated: ${date}\n`);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log('Supported providers:');
|
|
62
|
+
Object.entries(SUPPORTED_PROVIDERS).forEach(([id, info]) => {
|
|
63
|
+
const configured = providers.find(p => p.provider === id) ? '✅' : '⬚';
|
|
64
|
+
console.log(` ${configured} ${id.padEnd(12)} - ${info.description}`);
|
|
65
|
+
});
|
|
66
|
+
console.log('');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (action === 'set') {
|
|
71
|
+
if (!provider || !key) {
|
|
72
|
+
console.error('\n❌ Usage: nexuscli api set <provider> <key>\n');
|
|
73
|
+
console.log('Example:');
|
|
74
|
+
console.log(' nexuscli api set deepseek sk-7cb389cf4f8d421a977d9ec5daf7457b\n');
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const providerLower = provider.toLowerCase();
|
|
79
|
+
const info = SUPPORTED_PROVIDERS[providerLower];
|
|
80
|
+
|
|
81
|
+
if (!info) {
|
|
82
|
+
console.error(`\n❌ Unknown provider: ${provider}`);
|
|
83
|
+
console.log('\nSupported providers:');
|
|
84
|
+
Object.keys(SUPPORTED_PROVIDERS).forEach(p => console.log(` - ${p}`));
|
|
85
|
+
console.log('');
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Basic key validation
|
|
90
|
+
if (key.length < 10) {
|
|
91
|
+
console.error('\n❌ API key seems too short. Please check and try again.\n');
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const success = setApiKey(providerLower, key);
|
|
96
|
+
|
|
97
|
+
if (success) {
|
|
98
|
+
console.log(`\n✅ ${info.name} API key saved successfully!\n`);
|
|
99
|
+
console.log(` Provider: ${providerLower}`);
|
|
100
|
+
console.log(` Key: ${key.substring(0, 8)}${'*'.repeat(key.length - 12)}${key.slice(-4)}\n`);
|
|
101
|
+
} else {
|
|
102
|
+
console.error('\n❌ Failed to save API key. Check database.\n');
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (action === 'delete' || action === 'remove') {
|
|
109
|
+
if (!provider) {
|
|
110
|
+
console.error('\n❌ Usage: nexuscli api delete <provider>\n');
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const providerLower = provider.toLowerCase();
|
|
115
|
+
const success = deleteApiKey(providerLower);
|
|
116
|
+
|
|
117
|
+
if (success) {
|
|
118
|
+
console.log(`\n✅ API key for ${providerLower} deleted.\n`);
|
|
119
|
+
} else {
|
|
120
|
+
console.error(`\n❌ Failed to delete API key for ${providerLower}.\n`);
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (action === 'test') {
|
|
127
|
+
if (!provider) {
|
|
128
|
+
console.error('\n❌ Usage: nexuscli api test <provider>\n');
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const providerLower = provider.toLowerCase();
|
|
133
|
+
const apiKey = getApiKey(providerLower);
|
|
134
|
+
|
|
135
|
+
if (!apiKey) {
|
|
136
|
+
console.error(`\n❌ No API key configured for ${providerLower}`);
|
|
137
|
+
console.log(`\n Run: nexuscli api set ${providerLower} <your-key>\n`);
|
|
138
|
+
process.exit(1);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
console.log(`\n🔑 ${providerLower} API key found: ${apiKey.substring(0, 8)}...${apiKey.slice(-4)}\n`);
|
|
142
|
+
// TODO: Add actual API test call
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Unknown action
|
|
147
|
+
console.error(`\n❌ Unknown action: ${action}`);
|
|
148
|
+
console.log('\nUsage:');
|
|
149
|
+
console.log(' nexuscli api list - List configured providers');
|
|
150
|
+
console.log(' nexuscli api set <provider> <key> - Set API key');
|
|
151
|
+
console.log(' nexuscli api delete <provider> - Delete API key');
|
|
152
|
+
console.log(' nexuscli api test <provider> - Test API key\n');
|
|
153
|
+
process.exit(1);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = apiCommand;
|
package/lib/cli/boot.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nexuscli boot - Termux boot integration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
|
|
8
|
+
const { isInitialized, getConfig, setConfigValue } = require('../config/manager');
|
|
9
|
+
const { PATHS, ensureBootDirectory } = require('../utils/paths');
|
|
10
|
+
const { isTermux } = require('../utils/termux');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Boot script content
|
|
14
|
+
*/
|
|
15
|
+
function generateBootScript(config) {
|
|
16
|
+
const port = config.server?.port || 41800;
|
|
17
|
+
|
|
18
|
+
return `#!/data/data/com.termux/files/usr/bin/bash
|
|
19
|
+
# NexusCLI Auto-Start
|
|
20
|
+
# Generated by: nexuscli boot enable
|
|
21
|
+
|
|
22
|
+
# Acquire wake lock to keep CPU active
|
|
23
|
+
termux-wake-lock
|
|
24
|
+
|
|
25
|
+
# Wait for network initialization
|
|
26
|
+
sleep 3
|
|
27
|
+
|
|
28
|
+
# Start NexusCLI daemon
|
|
29
|
+
nexuscli start --daemon
|
|
30
|
+
|
|
31
|
+
# Send notification
|
|
32
|
+
termux-notification \\
|
|
33
|
+
--id nexuscli \\
|
|
34
|
+
--title "NexusCLI" \\
|
|
35
|
+
--content "Server running on port ${port}" \\
|
|
36
|
+
--priority high
|
|
37
|
+
`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Enable boot start
|
|
42
|
+
*/
|
|
43
|
+
function enableBoot(config) {
|
|
44
|
+
ensureBootDirectory();
|
|
45
|
+
|
|
46
|
+
const script = generateBootScript(config);
|
|
47
|
+
fs.writeFileSync(PATHS.BOOT_SCRIPT, script);
|
|
48
|
+
fs.chmodSync(PATHS.BOOT_SCRIPT, 0o755);
|
|
49
|
+
|
|
50
|
+
setConfigValue('termux.boot_start', true);
|
|
51
|
+
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Disable boot start
|
|
57
|
+
*/
|
|
58
|
+
function disableBoot() {
|
|
59
|
+
try {
|
|
60
|
+
if (fs.existsSync(PATHS.BOOT_SCRIPT)) {
|
|
61
|
+
fs.unlinkSync(PATHS.BOOT_SCRIPT);
|
|
62
|
+
}
|
|
63
|
+
setConfigValue('termux.boot_start', false);
|
|
64
|
+
return true;
|
|
65
|
+
} catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Check boot status
|
|
72
|
+
*/
|
|
73
|
+
function getBootStatus() {
|
|
74
|
+
const scriptExists = fs.existsSync(PATHS.BOOT_SCRIPT);
|
|
75
|
+
const config = getConfig();
|
|
76
|
+
const configEnabled = config.termux?.boot_start === true;
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
enabled: scriptExists && configEnabled,
|
|
80
|
+
scriptExists,
|
|
81
|
+
configEnabled,
|
|
82
|
+
scriptPath: PATHS.BOOT_SCRIPT
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Main boot command
|
|
88
|
+
*/
|
|
89
|
+
async function boot(action) {
|
|
90
|
+
console.log('');
|
|
91
|
+
|
|
92
|
+
// Check Termux
|
|
93
|
+
if (!isTermux()) {
|
|
94
|
+
console.log(chalk.yellow('Boot integration is only available on Termux.'));
|
|
95
|
+
console.log('');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!isInitialized()) {
|
|
100
|
+
console.log(chalk.yellow('NexusCLI is not configured.'));
|
|
101
|
+
console.log(`Run ${chalk.cyan('nexuscli init')} first.`);
|
|
102
|
+
console.log('');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const config = getConfig();
|
|
107
|
+
|
|
108
|
+
// Enable
|
|
109
|
+
if (action === 'enable') {
|
|
110
|
+
if (enableBoot(config)) {
|
|
111
|
+
console.log(chalk.green(' ✓ Boot auto-start enabled'));
|
|
112
|
+
console.log(chalk.gray(` Script: ${PATHS.BOOT_SCRIPT}`));
|
|
113
|
+
console.log('');
|
|
114
|
+
console.log(chalk.cyan(' Make sure Termux:Boot app is installed from F-Droid'));
|
|
115
|
+
} else {
|
|
116
|
+
console.log(chalk.red(' ✗ Failed to enable boot'));
|
|
117
|
+
}
|
|
118
|
+
console.log('');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Disable
|
|
123
|
+
if (action === 'disable') {
|
|
124
|
+
if (disableBoot()) {
|
|
125
|
+
console.log(chalk.green(' ✓ Boot auto-start disabled'));
|
|
126
|
+
} else {
|
|
127
|
+
console.log(chalk.red(' ✗ Failed to disable boot'));
|
|
128
|
+
}
|
|
129
|
+
console.log('');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Status
|
|
134
|
+
if (action === 'status') {
|
|
135
|
+
const status = getBootStatus();
|
|
136
|
+
|
|
137
|
+
console.log(chalk.bold('Boot Status:'));
|
|
138
|
+
console.log('');
|
|
139
|
+
|
|
140
|
+
if (status.enabled) {
|
|
141
|
+
console.log(chalk.green(' ✓ Auto-start is ENABLED'));
|
|
142
|
+
} else {
|
|
143
|
+
console.log(chalk.yellow(' ○ Auto-start is DISABLED'));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
console.log('');
|
|
147
|
+
console.log(` Script exists: ${status.scriptExists ? chalk.green('yes') : chalk.gray('no')}`);
|
|
148
|
+
console.log(` Config enabled: ${status.configEnabled ? chalk.green('yes') : chalk.gray('no')}`);
|
|
149
|
+
|
|
150
|
+
if (status.scriptExists) {
|
|
151
|
+
console.log(chalk.gray(` Path: ${status.scriptPath}`));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log('');
|
|
155
|
+
console.log(chalk.cyan(' Requirements:'));
|
|
156
|
+
console.log(' 1. Termux:Boot app installed from F-Droid');
|
|
157
|
+
console.log(' 2. Boot script in ~/.termux/boot/');
|
|
158
|
+
console.log(' 3. Battery optimization disabled for Termux');
|
|
159
|
+
console.log('');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Unknown action
|
|
164
|
+
console.log(chalk.red(`Unknown action: ${action}`));
|
|
165
|
+
console.log('Usage:');
|
|
166
|
+
console.log(' nexuscli boot enable Enable auto-start');
|
|
167
|
+
console.log(' nexuscli boot disable Disable auto-start');
|
|
168
|
+
console.log(' nexuscli boot status Show status');
|
|
169
|
+
console.log('');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports = boot;
|