@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.
Files changed (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/bin/nexuscli.js +117 -0
  4. package/frontend/dist/apple-touch-icon.png +0 -0
  5. package/frontend/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  6. package/frontend/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  7. package/frontend/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  8. package/frontend/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  9. package/frontend/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  10. package/frontend/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  11. package/frontend/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  12. package/frontend/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  13. package/frontend/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  14. package/frontend/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  15. package/frontend/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  16. package/frontend/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  17. package/frontend/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  18. package/frontend/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  19. package/frontend/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  20. package/frontend/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  21. package/frontend/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  22. package/frontend/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  23. package/frontend/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  24. package/frontend/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  25. package/frontend/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  26. package/frontend/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  27. package/frontend/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  28. package/frontend/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  29. package/frontend/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  30. package/frontend/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  31. package/frontend/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  32. package/frontend/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  33. package/frontend/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  34. package/frontend/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  35. package/frontend/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  36. package/frontend/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  37. package/frontend/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  38. package/frontend/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  39. package/frontend/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  40. package/frontend/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  41. package/frontend/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  42. package/frontend/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  43. package/frontend/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  44. package/frontend/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  45. package/frontend/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  46. package/frontend/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  47. package/frontend/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  48. package/frontend/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  49. package/frontend/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  50. package/frontend/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  51. package/frontend/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  52. package/frontend/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  53. package/frontend/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  54. package/frontend/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  55. package/frontend/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  56. package/frontend/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  57. package/frontend/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  58. package/frontend/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  59. package/frontend/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  60. package/frontend/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  61. package/frontend/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  62. package/frontend/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  63. package/frontend/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  64. package/frontend/dist/assets/index-Bn_l1e6e.css +1 -0
  65. package/frontend/dist/assets/index-CikJbUR5.js +8617 -0
  66. package/frontend/dist/browserconfig.xml +12 -0
  67. package/frontend/dist/favicon-16x16.png +0 -0
  68. package/frontend/dist/favicon-32x32.png +0 -0
  69. package/frontend/dist/favicon-48x48.png +0 -0
  70. package/frontend/dist/favicon.ico +0 -0
  71. package/frontend/dist/icon-192.png +0 -0
  72. package/frontend/dist/icon-512.png +0 -0
  73. package/frontend/dist/icon-maskable-192.png +0 -0
  74. package/frontend/dist/icon-maskable-512.png +0 -0
  75. package/frontend/dist/index.html +79 -0
  76. package/frontend/dist/manifest.json +75 -0
  77. package/frontend/dist/sw.js +122 -0
  78. package/frontend/package.json +28 -0
  79. package/lib/cli/api.js +156 -0
  80. package/lib/cli/boot.js +172 -0
  81. package/lib/cli/config.js +185 -0
  82. package/lib/cli/engines.js +257 -0
  83. package/lib/cli/init.js +660 -0
  84. package/lib/cli/logs.js +72 -0
  85. package/lib/cli/start.js +220 -0
  86. package/lib/cli/status.js +187 -0
  87. package/lib/cli/stop.js +64 -0
  88. package/lib/cli/uninstall.js +194 -0
  89. package/lib/cli/users.js +295 -0
  90. package/lib/cli/workspaces.js +337 -0
  91. package/lib/config/manager.js +233 -0
  92. package/lib/server/.env.example +20 -0
  93. package/lib/server/db/adapter.js +314 -0
  94. package/lib/server/db/drivers/better-sqlite3.js +38 -0
  95. package/lib/server/db/drivers/sql-js.js +75 -0
  96. package/lib/server/db/migrate.js +174 -0
  97. package/lib/server/db/migrations/001_ultra_light_schema.sql +96 -0
  98. package/lib/server/db/migrations/002_session_conversation_mapping.sql +19 -0
  99. package/lib/server/db/migrations/003_message_engine_tracking.sql +18 -0
  100. package/lib/server/db/migrations/004_performance_indexes.sql +16 -0
  101. package/lib/server/db.js +2 -0
  102. package/lib/server/lib/cli-wrapper.js +164 -0
  103. package/lib/server/lib/output-parser.js +132 -0
  104. package/lib/server/lib/pty-adapter.js +57 -0
  105. package/lib/server/middleware/auth.js +103 -0
  106. package/lib/server/models/Conversation.js +259 -0
  107. package/lib/server/models/Message.js +228 -0
  108. package/lib/server/models/User.js +115 -0
  109. package/lib/server/package-lock.json +5895 -0
  110. package/lib/server/routes/auth.js +168 -0
  111. package/lib/server/routes/chat.js +206 -0
  112. package/lib/server/routes/codex.js +205 -0
  113. package/lib/server/routes/conversations.js +224 -0
  114. package/lib/server/routes/gemini.js +228 -0
  115. package/lib/server/routes/jobs.js +317 -0
  116. package/lib/server/routes/messages.js +60 -0
  117. package/lib/server/routes/models.js +198 -0
  118. package/lib/server/routes/sessions.js +285 -0
  119. package/lib/server/routes/upload.js +134 -0
  120. package/lib/server/routes/wake-lock.js +95 -0
  121. package/lib/server/routes/workspace.js +80 -0
  122. package/lib/server/routes/workspaces.js +142 -0
  123. package/lib/server/scripts/cleanup-ghost-sessions.js +71 -0
  124. package/lib/server/scripts/seed-users.js +37 -0
  125. package/lib/server/scripts/test-history-access.js +50 -0
  126. package/lib/server/server.js +227 -0
  127. package/lib/server/services/cache.js +85 -0
  128. package/lib/server/services/claude-wrapper.js +312 -0
  129. package/lib/server/services/cli-loader.js +384 -0
  130. package/lib/server/services/codex-output-parser.js +277 -0
  131. package/lib/server/services/codex-wrapper.js +224 -0
  132. package/lib/server/services/context-bridge.js +289 -0
  133. package/lib/server/services/gemini-output-parser.js +398 -0
  134. package/lib/server/services/gemini-wrapper.js +249 -0
  135. package/lib/server/services/history-sync.js +407 -0
  136. package/lib/server/services/output-parser.js +415 -0
  137. package/lib/server/services/session-manager.js +465 -0
  138. package/lib/server/services/summary-generator.js +259 -0
  139. package/lib/server/services/workspace-manager.js +516 -0
  140. package/lib/server/tests/history-sync.test.js +90 -0
  141. package/lib/server/tests/integration-session-sync.test.js +151 -0
  142. package/lib/server/tests/integration.test.js +76 -0
  143. package/lib/server/tests/performance.test.js +118 -0
  144. package/lib/server/tests/services.test.js +160 -0
  145. package/lib/setup/postinstall.js +216 -0
  146. package/lib/utils/paths.js +107 -0
  147. package/lib/utils/termux.js +145 -0
  148. 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
@@ -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;
@@ -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;