upfynai-code 3.0.4 → 3.2.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 (258) hide show
  1. package/README.md +69 -92
  2. package/bin/cli.js +191 -0
  3. package/dist/client/assets/AppContent-M14Au3SB.js +542 -0
  4. package/{client/dist/assets/BrowserPanel-0TLEl-IC.js → dist/client/assets/BrowserPanel-TFKm2NDJ.js} +2 -2
  5. package/dist/client/assets/DashboardPanel-C88HjsCh.js +1 -0
  6. package/dist/client/assets/FileTree-DvO1xnDE.js +1 -0
  7. package/{client/dist/assets/GitPanel-C_xFM-N2.js → dist/client/assets/GitPanel-D-slVlyy.js} +2 -2
  8. package/dist/client/assets/LoginModal-Chi4SYcr.js +21 -0
  9. package/{client/dist/assets/MarkdownPreview-CESjI261.js → dist/client/assets/MarkdownPreview-CuIix2u9.js} +1 -1
  10. package/dist/client/assets/MermaidBlock-Dq9uFv82.js +2 -0
  11. package/dist/client/assets/Onboarding-QYXx24dX.js +1 -0
  12. package/{client/dist/assets/PreviewPanel-CqCa92Tf.js → dist/client/assets/PreviewPanel-Dd8q-jo0.js} +1 -1
  13. package/dist/client/assets/SetupForm-CrspaUva.js +1 -0
  14. package/dist/client/assets/WorkflowsPanel-DIlYAdhB.js +1 -0
  15. package/dist/client/assets/index-CnNNzw9A.css +1 -0
  16. package/{client/dist/assets/index-HaY-3pK1.js → dist/client/assets/index-rUkK9FDP.js} +26 -26
  17. package/{client/dist/assets/vendor-codemirror-D2ALgpaX.js → dist/client/assets/vendor-codemirror-jc6nyJQg.js} +1 -1
  18. package/{client/dist/assets/vendor-diff-DNQpbhrT.js → dist/client/assets/vendor-diff-THJmAcEI.js} +1 -1
  19. package/{client/dist/assets/vendor-icons-GyYE35HP.js → dist/client/assets/vendor-icons-CfjIpdrD.js} +145 -155
  20. package/{client/dist/assets/vendor-markdown-CimbIo6Y.js → dist/client/assets/vendor-markdown-Cdm6NEGf.js} +1 -1
  21. package/dist/client/assets/vendor-mermaid-DTPaBx-U.js +2559 -0
  22. package/{client/dist/assets/vendor-react-96lCPsRK.js → dist/client/assets/vendor-react-wFkb6mSf.js} +1 -1
  23. package/{client/dist/assets/vendor-syntax-LS_Nt30I.js → dist/client/assets/vendor-syntax-C_UZR7tc.js} +1 -1
  24. package/dist/client/favicon.png +0 -0
  25. package/dist/client/icons/icon-128x128.png +0 -0
  26. package/dist/client/icons/icon-144x144.png +0 -0
  27. package/dist/client/icons/icon-152x152.png +0 -0
  28. package/dist/client/icons/icon-192x192.png +0 -0
  29. package/dist/client/icons/icon-384x384.png +0 -0
  30. package/dist/client/icons/icon-512x512.png +0 -0
  31. package/dist/client/icons/icon-72x72.png +0 -0
  32. package/dist/client/icons/icon-96x96.png +0 -0
  33. package/{client/dist → dist/client}/index.html +37 -36
  34. package/dist/client/logo-128.png +0 -0
  35. package/dist/client/logo-256.png +0 -0
  36. package/dist/client/logo-32.png +0 -0
  37. package/dist/client/logo-512.png +0 -0
  38. package/dist/client/logo-64.png +0 -0
  39. package/dist/client/logo.png +0 -0
  40. package/{client/dist → dist/client}/manifest.json +12 -12
  41. package/{client/dist → dist/client}/mcp-docs.html +1 -1
  42. package/{client/dist → dist/client}/sw.js +2 -2
  43. package/package.json +56 -105
  44. package/scripts/postinstall.js +9 -0
  45. package/scripts/prepublish.js +77 -0
  46. package/src/animation.js +228 -0
  47. package/src/auth.js +142 -0
  48. package/src/config.js +40 -0
  49. package/src/connect.js +416 -0
  50. package/src/launch.js +81 -0
  51. package/src/mcp.js +57 -0
  52. package/src/permissions.js +140 -0
  53. package/src/persistent-shell.js +261 -0
  54. package/src/server.js +54 -0
  55. package/client/dist/assets/AppContent-CwrTP6TW.js +0 -545
  56. package/client/dist/assets/CanvasFullScreen-D1GWQsGL.js +0 -1
  57. package/client/dist/assets/CanvasWorkspace-D7ORj358.js +0 -163
  58. package/client/dist/assets/DashboardPanel-BV7ybUDe.js +0 -1
  59. package/client/dist/assets/FileTree-5qfhBqdE.js +0 -1
  60. package/client/dist/assets/LoginModal-CImJHRjX.js +0 -13
  61. package/client/dist/assets/MermaidBlock-BFM21cwe.js +0 -2
  62. package/client/dist/assets/Onboarding-B3cteLu2.js +0 -1
  63. package/client/dist/assets/SetupForm-P6dsYgHO.js +0 -1
  64. package/client/dist/assets/WorkflowsPanel-CBoN80kc.js +0 -1
  65. package/client/dist/assets/index-46kkVu2i.css +0 -1
  66. package/client/dist/assets/pdf-CE_K4jFx.js +0 -12
  67. package/client/dist/assets/vendor-canvas-BZV40eAE.css +0 -1
  68. package/client/dist/assets/vendor-canvas-DvHJ_Pn2.js +0 -49
  69. package/client/dist/assets/vendor-mermaid-DucWyDEe.js +0 -2556
  70. package/client/dist/favicon.png +0 -0
  71. package/client/dist/icons/icon-128x128.png +0 -0
  72. package/client/dist/icons/icon-144x144.png +0 -0
  73. package/client/dist/icons/icon-152x152.png +0 -0
  74. package/client/dist/icons/icon-192x192.png +0 -0
  75. package/client/dist/icons/icon-384x384.png +0 -0
  76. package/client/dist/icons/icon-512x512.png +0 -0
  77. package/client/dist/icons/icon-72x72.png +0 -0
  78. package/client/dist/icons/icon-96x96.png +0 -0
  79. package/client/dist/logo-128.png +0 -0
  80. package/client/dist/logo-256.png +0 -0
  81. package/client/dist/logo-32.png +0 -0
  82. package/client/dist/logo-512.png +0 -0
  83. package/client/dist/logo-64.png +0 -0
  84. package/commands/upfynai-connect.md +0 -59
  85. package/commands/upfynai-disconnect.md +0 -31
  86. package/commands/upfynai-doctor.md +0 -99
  87. package/commands/upfynai-export.md +0 -49
  88. package/commands/upfynai-local.md +0 -82
  89. package/commands/upfynai-status.md +0 -75
  90. package/commands/upfynai-stop.md +0 -49
  91. package/commands/upfynai-uninstall.md +0 -58
  92. package/commands/upfynai.md +0 -69
  93. package/scripts/build-client.js +0 -17
  94. package/scripts/fix-node-pty.js +0 -67
  95. package/scripts/install-commands.js +0 -78
  96. package/server/agent-loop.js +0 -242
  97. package/server/auto-compact.js +0 -99
  98. package/server/browser.js +0 -131
  99. package/server/claude-sdk.js +0 -797
  100. package/server/cli-ui.js +0 -798
  101. package/server/cli.js +0 -751
  102. package/server/constants/config.js +0 -31
  103. package/server/cursor-cli.js +0 -270
  104. package/server/database/auth.db +0 -0
  105. package/server/database/db.js +0 -1547
  106. package/server/database/init.sql +0 -70
  107. package/server/index.js +0 -3813
  108. package/server/load-env.js +0 -26
  109. package/server/mcp-server.js +0 -621
  110. package/server/middleware/auth.js +0 -184
  111. package/server/middleware/relayHelpers.js +0 -44
  112. package/server/middleware/sandboxRouter.js +0 -174
  113. package/server/openai-codex.js +0 -403
  114. package/server/openrouter.js +0 -137
  115. package/server/projects.js +0 -1807
  116. package/server/provider-factory.js +0 -174
  117. package/server/relay-client.js +0 -390
  118. package/server/routes/agent.js +0 -1234
  119. package/server/routes/auth.js +0 -559
  120. package/server/routes/browser.js +0 -419
  121. package/server/routes/canvas.js +0 -53
  122. package/server/routes/cli-auth.js +0 -263
  123. package/server/routes/codex.js +0 -396
  124. package/server/routes/commands.js +0 -707
  125. package/server/routes/composio.js +0 -176
  126. package/server/routes/cursor.js +0 -770
  127. package/server/routes/dashboard.js +0 -295
  128. package/server/routes/git.js +0 -1208
  129. package/server/routes/keys.js +0 -34
  130. package/server/routes/mcp-utils.js +0 -48
  131. package/server/routes/mcp.js +0 -661
  132. package/server/routes/payments.js +0 -227
  133. package/server/routes/projects.js +0 -754
  134. package/server/routes/sessions.js +0 -146
  135. package/server/routes/settings.js +0 -261
  136. package/server/routes/taskmaster.js +0 -1928
  137. package/server/routes/user.js +0 -106
  138. package/server/routes/vapi-chat.js +0 -624
  139. package/server/routes/voice.js +0 -235
  140. package/server/routes/webhooks.js +0 -166
  141. package/server/routes/workflows.js +0 -312
  142. package/server/sandbox.js +0 -120
  143. package/server/services/browser-ai.js +0 -154
  144. package/server/services/composio.js +0 -204
  145. package/server/services/sessionRegistry.js +0 -139
  146. package/server/services/whisperService.js +0 -84
  147. package/server/services/workflowScheduler.js +0 -211
  148. package/server/tests/relay-flow.test.js +0 -570
  149. package/server/tests/sessions.test.js +0 -259
  150. package/server/utils/commandParser.js +0 -303
  151. package/server/utils/email.js +0 -66
  152. package/server/utils/gitConfig.js +0 -24
  153. package/server/utils/mcp-detector.js +0 -198
  154. package/server/utils/taskmaster-websocket.js +0 -129
  155. package/shared/integrationCatalog.d.ts +0 -12
  156. package/shared/integrationCatalog.js +0 -172
  157. package/shared/modelConstants.js +0 -96
  158. /package/{shared → dist}/agents/claude.js +0 -0
  159. /package/{shared → dist}/agents/codex.js +0 -0
  160. /package/{shared → dist}/agents/cursor.js +0 -0
  161. /package/{shared → dist}/agents/detect.js +0 -0
  162. /package/{shared → dist}/agents/exec.js +0 -0
  163. /package/{shared → dist}/agents/files.js +0 -0
  164. /package/{shared → dist}/agents/git.js +0 -0
  165. /package/{shared → dist}/agents/gitagent.js +0 -0
  166. /package/{shared → dist}/agents/index.js +0 -0
  167. /package/{shared → dist}/agents/shell.js +0 -0
  168. /package/{shared → dist}/agents/utils.js +0 -0
  169. /package/{client/dist → dist/client}/api-docs.html +0 -0
  170. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  171. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  172. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  173. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  174. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  175. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  176. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  177. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  178. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  179. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  180. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  181. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  182. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  183. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  184. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  185. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  186. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  187. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  188. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  189. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  190. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  191. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  192. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  193. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  194. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  195. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  196. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  197. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  198. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  199. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  200. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  201. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  202. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  203. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  204. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  205. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  206. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  207. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  208. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  209. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  210. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  211. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  212. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  213. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  214. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  215. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  216. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  217. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  218. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  219. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  220. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  221. /package/{client/dist → dist/client}/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  222. /package/{client/dist → dist/client}/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  223. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  224. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  225. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  226. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  227. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  228. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  229. /package/{client/dist → dist/client}/assets/vendor-i18n-DCFGyhQR.js +0 -0
  230. /package/{client/dist → dist/client}/assets/vendor-xterm-CZq1hqo1.js +0 -0
  231. /package/{client/dist → dist/client}/assets/vendor-xterm-qxJ8_QYu.css +0 -0
  232. /package/{client/dist → dist/client}/clear-cache.html +0 -0
  233. /package/{client/dist → dist/client}/convert-icons.md +0 -0
  234. /package/{client/dist → dist/client}/favicon.svg +0 -0
  235. /package/{client/dist → dist/client}/generate-icons.js +0 -0
  236. /package/{client/dist → dist/client}/icons/claude-ai-icon.svg +0 -0
  237. /package/{client/dist → dist/client}/icons/codex-white.svg +0 -0
  238. /package/{client/dist → dist/client}/icons/codex.svg +0 -0
  239. /package/{client/dist → dist/client}/icons/cursor-white.svg +0 -0
  240. /package/{client/dist → dist/client}/icons/cursor.svg +0 -0
  241. /package/{client/dist → dist/client}/icons/icon-128x128.svg +0 -0
  242. /package/{client/dist → dist/client}/icons/icon-144x144.svg +0 -0
  243. /package/{client/dist → dist/client}/icons/icon-152x152.svg +0 -0
  244. /package/{client/dist → dist/client}/icons/icon-192x192.svg +0 -0
  245. /package/{client/dist → dist/client}/icons/icon-384x384.svg +0 -0
  246. /package/{client/dist → dist/client}/icons/icon-512x512.svg +0 -0
  247. /package/{client/dist → dist/client}/icons/icon-72x72.svg +0 -0
  248. /package/{client/dist → dist/client}/icons/icon-96x96.svg +0 -0
  249. /package/{client/dist → dist/client}/icons/icon-template.svg +0 -0
  250. /package/{client/dist → dist/client}/logo.svg +0 -0
  251. /package/{client/dist → dist/client}/offline.html +0 -0
  252. /package/{client/dist → dist/client}/screenshots/cli-selection.png +0 -0
  253. /package/{client/dist → dist/client}/screenshots/desktop-main.png +0 -0
  254. /package/{client/dist → dist/client}/screenshots/mobile-chat.png +0 -0
  255. /package/{client/dist → dist/client}/screenshots/tools-modal.png +0 -0
  256. /package/{shared → dist}/gitagent/index.js +0 -0
  257. /package/{shared → dist}/gitagent/parser.js +0 -0
  258. /package/{shared → dist}/gitagent/prompt-builder.js +0 -0
package/server/cli.js DELETED
@@ -1,751 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Upfyn-Code CLI
4
- * by Thinqmesh Technologies
5
- *
6
- * Visual AI coding interface with Upfyn-Canvas for AI coding assistants
7
- *
8
- * Commands:
9
- * (no args) - Launch Claude Code with Upfyn branding (default)
10
- * start - Start the local server (web UI)
11
- * stop - Stop a running server
12
- * connect - Connect to hosted server (relay bridge)
13
- * config - View/set configuration (API key, server, etc.)
14
- * status - Show configuration and data locations
15
- * update - Update to the latest version
16
- * reset - Clear local database
17
- * uninstall - Remove all data, config, and slash commands
18
- * help - Show help information
19
- * version - Show version information
20
- */
21
-
22
- import fs from 'fs';
23
- import path from 'path';
24
- import os from 'os';
25
- import { fileURLToPath } from 'url';
26
- import { dirname } from 'path';
27
- import { execSync, spawn } from 'child_process';
28
- import {
29
- c,
30
- showStyledHelp,
31
- showStyledStatus,
32
- showServerBanner,
33
- showConnectStartup,
34
- showConnectionBanner,
35
- showLaunchScreen,
36
- showConfig,
37
- logRelayEvent,
38
- createSpinner,
39
- playRocketAnimation,
40
- clearScreen,
41
- } from './cli-ui.js';
42
-
43
- const __filename = fileURLToPath(import.meta.url);
44
- const __dirname = dirname(__filename);
45
-
46
- // Load package.json for version info
47
- const packageJsonPath = path.join(__dirname, '../package.json');
48
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
49
-
50
- const CONFIG_DIR = path.join(os.homedir(), '.upfynai');
51
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
52
- const PID_FILE = path.join(CONFIG_DIR, 'server.pid');
53
-
54
- /** Mask internal Railway URL for display */
55
- function displayServerUrl(url) {
56
- if (!url || url === 'https://upfynai-code-production.up.railway.app') return 'Upfyn Cloud';
57
- try { return new URL(url).host; } catch { return url; }
58
- }
59
-
60
- // Load environment variables from .env file if it exists
61
- function loadEnvFile() {
62
- try {
63
- const envPath = path.join(__dirname, '../.env');
64
- const envFile = fs.readFileSync(envPath, 'utf8');
65
- envFile.split('\n').forEach(line => {
66
- const trimmedLine = line.trim();
67
- if (trimmedLine && !trimmedLine.startsWith('#')) {
68
- const [key, ...valueParts] = trimmedLine.split('=');
69
- if (key && valueParts.length > 0 && !process.env[key]) {
70
- process.env[key] = valueParts.join('=').trim();
71
- }
72
- }
73
- });
74
- } catch (e) {
75
- // .env file is optional
76
- }
77
- }
78
-
79
- // Load saved config from ~/.upfynai/config.json
80
- function loadConfig() {
81
- try {
82
- if (fs.existsSync(CONFIG_FILE)) {
83
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
84
- }
85
- } catch (e) { /* ignore */ }
86
- return {};
87
- }
88
-
89
- // Save config to ~/.upfynai/config.json
90
- function saveConfig(config) {
91
- if (!fs.existsSync(CONFIG_DIR)) {
92
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
93
- }
94
- // Don't save internal keys
95
- const { _path, ...rest } = config;
96
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(rest, null, 2));
97
- }
98
-
99
- // Get the database path (same logic as db.js)
100
- function getDatabasePath() {
101
- loadEnvFile();
102
- return process.env.DATABASE_PATH || path.join(__dirname, 'database', 'auth.db');
103
- }
104
-
105
- // Get the installation directory
106
- function getInstallDir() {
107
- return path.join(__dirname, '..');
108
- }
109
-
110
- // --- OS Detection + Claude Binary Discovery ---
111
-
112
- function findClaudeBinary() {
113
- const isWindows = process.platform === 'win32';
114
- const candidates = isWindows
115
- ? ['claude.exe', 'claude.cmd', 'claude']
116
- : ['claude'];
117
-
118
- for (const cmd of candidates) {
119
- try {
120
- const whichCmd = isWindows ? 'where' : 'which';
121
- const result = execSync(`${whichCmd} ${cmd}`, { stdio: 'pipe', encoding: 'utf8' }).trim();
122
- if (result) return cmd;
123
- } catch {
124
- // not found, try next
125
- }
126
- }
127
- return null;
128
- }
129
-
130
- // Check if a server is running via PID file
131
- function isServerRunning() {
132
- if (!fs.existsSync(PID_FILE)) return false;
133
- try {
134
- const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
135
- process.kill(pid, 0); // signal 0 = check if alive
136
- return pid;
137
- } catch {
138
- // Process not running, clean up stale PID file
139
- try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }
140
- return false;
141
- }
142
- }
143
-
144
- // --- Show status command ---
145
- function showStatus() {
146
- const config = loadConfig();
147
- const installDir = getInstallDir();
148
- const dbPath = getDatabasePath();
149
- const dbExists = fs.existsSync(dbPath);
150
- let dbSize = '';
151
- if (dbExists) {
152
- const stats = fs.statSync(dbPath);
153
- dbSize = (stats.size / 1024).toFixed(2) + ' KB';
154
- }
155
-
156
- const serverPid = isServerRunning();
157
-
158
- showStyledStatus({
159
- version: packageJson.version,
160
- installDir,
161
- dbPath,
162
- dbExists,
163
- dbSize,
164
- port: process.env.PORT || '3001',
165
- portDefault: !process.env.PORT,
166
- claudeCli: findClaudeBinary() || null,
167
- apiKey: config.anthropicApiKey || null,
168
- serverRunning: serverPid,
169
- });
170
- }
171
-
172
- // Show help
173
- function showHelp() {
174
- showStyledHelp(packageJson.version);
175
- }
176
-
177
- // Show version
178
- function showVersion() {
179
- console.log(`${packageJson.version}`);
180
- }
181
-
182
- // Compare semver versions, returns true if v1 > v2
183
- function isNewerVersion(v1, v2) {
184
- const parts1 = v1.split('.').map(Number);
185
- const parts2 = v2.split('.').map(Number);
186
- for (let i = 0; i < 3; i++) {
187
- if (parts1[i] > parts2[i]) return true;
188
- if (parts1[i] < parts2[i]) return false;
189
- }
190
- return false;
191
- }
192
-
193
- // Check for updates
194
- async function checkForUpdates(silent = false) {
195
- try {
196
- const latestVersion = execSync('npm show upfynai-code version', { encoding: 'utf8' }).trim();
197
- const currentVersion = packageJson.version;
198
-
199
- if (isNewerVersion(latestVersion, currentVersion)) {
200
- if (!silent) {
201
- console.log(`\n ${c.yellow('!')} New version available: ${c.bBright(latestVersion)} ${c.dim(`(current: ${currentVersion})`)}`);
202
- console.log(` Run ${c.bright('uc update')} to update\n`);
203
- }
204
- return { hasUpdate: true, latestVersion, currentVersion };
205
- } else if (!silent) {
206
- console.log(` ${c.green('OK')} You are on the latest version (${currentVersion})`);
207
- }
208
- return { hasUpdate: false, latestVersion, currentVersion };
209
- } catch (e) {
210
- if (!silent) {
211
- console.log(` ${c.yellow('!')} Could not check for updates`);
212
- }
213
- return { hasUpdate: false, error: e.message };
214
- }
215
- }
216
-
217
- // Update the package
218
- async function updatePackage() {
219
- try {
220
- const spinner = createSpinner('Checking for updates...');
221
- spinner.start();
222
-
223
- const { hasUpdate, latestVersion, currentVersion } = await checkForUpdates(true);
224
- if (!hasUpdate) {
225
- spinner.stop(`Already on the latest version (${currentVersion})`);
226
- return;
227
- }
228
- spinner.stop(`Update available: ${currentVersion} -> ${latestVersion}`);
229
-
230
- const installSpinner = createSpinner(`Updating to v${latestVersion}...`);
231
- installSpinner.start();
232
- execSync('npm update -g upfynai-code', { stdio: 'pipe' });
233
- installSpinner.stop(`Updated to v${latestVersion}! Restart uc to use the new version.`);
234
- } catch (e) {
235
- console.log(` ${c.red('FAIL')} Update failed: ${e.message}`);
236
- console.log(` ${c.dim('Try running manually:')} ${c.bright('npm update -g upfynai-code')}`);
237
- }
238
- }
239
-
240
- // Install slash commands to ~/.claude/commands/
241
- async function installCommands(silent = false) {
242
- const commandsSource = path.join(__dirname, '..', 'commands');
243
- const commandsDest = path.join(os.homedir(), '.claude', 'commands');
244
-
245
- if (!fs.existsSync(commandsDest)) {
246
- fs.mkdirSync(commandsDest, { recursive: true });
247
- }
248
-
249
- if (!fs.existsSync(commandsSource)) {
250
- if (!silent) console.log(` ${c.red('FAIL')} Commands directory not found`);
251
- return 0;
252
- }
253
-
254
- const files = fs.readdirSync(commandsSource).filter(f => f.endsWith('.md'));
255
- let count = 0;
256
-
257
- for (const file of files) {
258
- fs.copyFileSync(
259
- path.join(commandsSource, file),
260
- path.join(commandsDest, file)
261
- );
262
- if (!silent) {
263
- console.log(` ${c.green('OK')} Installed ${c.violet('/' + file.replace('.md', ''))}`);
264
- }
265
- count++;
266
- }
267
-
268
- if (!silent) {
269
- console.log(`\n ${c.bBright(`${count} slash commands installed!`)}`);
270
- console.log(` ${c.dim('Available in your AI CLI as /upfynai-*')}\n`);
271
- }
272
- return count;
273
- }
274
-
275
- // Remove slash commands from ~/.claude/commands/
276
- async function uninstallCommands() {
277
- const commandsDest = path.join(os.homedir(), '.claude', 'commands');
278
- const files = fs.existsSync(commandsDest)
279
- ? fs.readdirSync(commandsDest).filter(f => f.startsWith('upfynai'))
280
- : [];
281
-
282
- if (files.length === 0) {
283
- console.log(` ${c.yellow('!')} No Upfyn-Code commands found to remove`);
284
- return;
285
- }
286
-
287
- for (const file of files) {
288
- fs.unlinkSync(path.join(commandsDest, file));
289
- console.log(` ${c.green('OK')} Removed ${c.violet('/' + file.replace('.md', ''))}`);
290
- }
291
-
292
- console.log(`\n ${c.bBright(`${files.length} slash commands removed.`)}\n`);
293
- }
294
-
295
- // --- Config command ---
296
- function handleConfig(options) {
297
- const config = loadConfig();
298
-
299
- if (options.apiKey) {
300
- // Set API key
301
- config.anthropicApiKey = options.apiKey;
302
- saveConfig(config);
303
- console.log(`\n ${c.green('OK')} ${c.white('Anthropic API key saved')}`);
304
- console.log(` ${c.dim('Key:')} sk-ant-...${options.apiKey.slice(-4)}`);
305
- console.log(` ${c.dim('Stored in:')} ${CONFIG_FILE}\n`);
306
- return;
307
- }
308
-
309
- if (options.clearApiKey) {
310
- delete config.anthropicApiKey;
311
- saveConfig(config);
312
- console.log(`\n ${c.green('OK')} ${c.white('Anthropic API key removed')}\n`);
313
- return;
314
- }
315
-
316
- // Show current config
317
- showConfig({ ...config, _path: CONFIG_FILE });
318
- }
319
-
320
- // --- First-run detection ---
321
- function isFirstRun() {
322
- return !fs.existsSync(CONFIG_FILE);
323
- }
324
-
325
- function showFirstRunWelcome() {
326
- const W = 58;
327
- const lines = [];
328
- lines.push('');
329
- lines.push(` ${c.bBright('Welcome to Upfyn-Code!')} ${c.dim('v' + packageJson.version)}`);
330
- lines.push(` ${c.dark('='.repeat(W))}`);
331
- lines.push('');
332
- lines.push(` ${c.white('Upfyn-Code gives you a visual AI coding interface')}`);
333
- lines.push(` ${c.white('for Claude Code, Cursor, and Codex — all in one place.')}`);
334
- lines.push('');
335
- lines.push(` ${c.bCyan('Quick start:')}`);
336
- lines.push(` ${c.bright('1.')} ${c.gray('Run')} ${c.cyan('uc')} ${c.gray('to launch with Claude Code')}`);
337
- lines.push(` ${c.bright('2.')} ${c.gray('Run')} ${c.cyan('uc start')} ${c.gray('for just the web UI')}`);
338
- lines.push(` ${c.bright('3.')} ${c.gray('Run')} ${c.cyan('uc connect --key <token>')} ${c.gray('to bridge to cli.upfyn.com')}`);
339
- lines.push('');
340
- lines.push(` ${c.bCyan('Optional setup:')}`);
341
- lines.push(` ${c.dim('$')} ${c.bright('uc config --api-key sk-ant-xxx')} ${c.dim('# Save your API key')}`);
342
- lines.push(` ${c.dim('$')} ${c.bright('uc install-commands')} ${c.dim('# Add slash commands')}`);
343
- lines.push('');
344
- lines.push(` ${c.dim('Run')} ${c.bright('uc help')} ${c.dim('for all commands.')}`);
345
- lines.push(` ${c.dark('='.repeat(W))}`);
346
- lines.push('');
347
- process.stdout.write(lines.join('\n') + '\n');
348
-
349
- // Create config dir so first-run only shows once
350
- if (!fs.existsSync(CONFIG_DIR)) {
351
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
352
- }
353
- saveConfig({});
354
- }
355
-
356
- // --- Launch Interactive (default command) ---
357
- async function launchInteractive() {
358
- // 0. Show first-run welcome if needed
359
- const firstRun = isFirstRun();
360
-
361
- // 1. Play rocket animation
362
- await playRocketAnimation();
363
- clearScreen();
364
-
365
- // 1.5 Show first-run tips (only once)
366
- if (firstRun) {
367
- showFirstRunWelcome();
368
- }
369
-
370
- // 2. Ensure slash commands are installed (silent)
371
- await installCommands(true);
372
-
373
- // 3. Find Claude Code binary
374
- const claudeBin = findClaudeBinary();
375
-
376
- // 4. Load config for relay + API key
377
- const config = loadConfig();
378
-
379
- // 5. Show launch screen
380
- showLaunchScreen(packageJson.version, claudeBin, {
381
- relayStatus: config.relayKey && config.server
382
- ? `Auto-connecting to ${displayServerUrl(config.server)}`
383
- : null,
384
- apiKey: config.anthropicApiKey || null,
385
- });
386
-
387
- // 6. If Claude Code not found, fall back to server mode
388
- if (!claudeBin) {
389
- console.log(` ${c.dim('Falling back to server mode...')}\n`);
390
- await startServer();
391
- return;
392
- }
393
-
394
- // 7. Build environment for Claude Code
395
- const childEnv = { ...process.env };
396
- if (config.anthropicApiKey) {
397
- childEnv.ANTHROPIC_API_KEY = config.anthropicApiKey;
398
- }
399
-
400
- // 8. Start the local web UI server in the background
401
- const port = process.env.PORT || '3001';
402
- process.env.VITE_IS_PLATFORM = 'true'; // local mode
403
- startBackgroundServer(port);
404
-
405
- // 9. Start background relay if config exists (for cloud mode)
406
- if (config.relayKey && config.server) {
407
- startBackgroundRelay(config);
408
- }
409
-
410
- // 10. Spawn Claude Code interactively
411
- const child = spawn(claudeBin, [], {
412
- stdio: 'inherit',
413
- cwd: process.cwd(),
414
- shell: true,
415
- env: childEnv,
416
- });
417
-
418
- child.on('exit', (code) => {
419
- process.exit(code || 0);
420
- });
421
-
422
- child.on('error', (err) => {
423
- console.log(`\n ${c.red('FAIL')} Failed to launch Claude Code: ${err.message}`);
424
- console.log(` ${c.dim('Make sure Claude Code is installed:')}`);
425
- console.log(` ${c.bright('npm install -g @anthropic-ai/claude-code')}\n`);
426
- process.exit(1);
427
- });
428
- }
429
-
430
- // --- Background server for local mode ---
431
- function startBackgroundServer(port) {
432
- // Start the server in the background so the web UI is available
433
- import('./index.js').then(() => {
434
- // Server started successfully in background
435
- }).catch(() => {
436
- // Server failed to start — user still has Claude Code CLI
437
- });
438
-
439
- // Open browser after a short delay
440
- setTimeout(() => {
441
- const url = `http://localhost:${port}`;
442
- try {
443
- const openCmd = process.platform === 'win32' ? 'start'
444
- : process.platform === 'darwin' ? 'open'
445
- : 'xdg-open';
446
- execSync(`${openCmd} ${url}`, { stdio: 'ignore' });
447
- } catch {
448
- // Browser open failed — not critical
449
- }
450
- }, 2000);
451
- }
452
-
453
- // --- Background relay connection ---
454
- function startBackgroundRelay(config) {
455
- // Import and start relay in background (non-blocking)
456
- import('./relay-client.js').then(({ connectToServerBackground }) => {
457
- if (typeof connectToServerBackground === 'function') {
458
- connectToServerBackground({
459
- server: config.server,
460
- key: config.relayKey,
461
- silent: true,
462
- });
463
- }
464
- }).catch(() => {
465
- // Relay module not available or no background connect — that's ok
466
- });
467
- }
468
-
469
- // Write PID file so `uc stop` can find and kill the server
470
- function writePidFile() {
471
- if (!fs.existsSync(CONFIG_DIR)) {
472
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
473
- }
474
- fs.writeFileSync(PID_FILE, String(process.pid));
475
- }
476
-
477
- // Remove PID file on exit
478
- function cleanupPidFile() {
479
- try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }
480
- }
481
-
482
- // Stop a running server
483
- function stopServer() {
484
- if (!fs.existsSync(PID_FILE)) {
485
- console.log(`\n ${c.yellow('!')} No running server found.`);
486
- console.log(` ${c.dim('Start one with:')} ${c.bright('uc start')}\n`);
487
- return;
488
- }
489
-
490
- try {
491
- const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
492
- process.kill(pid, 'SIGTERM');
493
- fs.unlinkSync(PID_FILE);
494
- console.log(`\n ${c.green('OK')} Server stopped (PID ${pid})\n`);
495
- } catch (e) {
496
- // Process might already be dead
497
- try { fs.unlinkSync(PID_FILE); } catch { /* ignore */ }
498
- if (e.code === 'ESRCH') {
499
- console.log(`\n ${c.yellow('!')} Server was not running (stale PID file removed)\n`);
500
- } else {
501
- console.log(`\n ${c.red('FAIL')} Could not stop server: ${e.message}\n`);
502
- }
503
- }
504
- }
505
-
506
- // Uninstall: remove config, database, slash commands
507
- function uninstallApp() {
508
- console.log(`\n ${c.bBright('Upfyn-Code — Uninstall')}`);
509
- console.log(` ${c.dark('='.repeat(40))}\n`);
510
-
511
- // 1. Stop any running server
512
- if (fs.existsSync(PID_FILE)) {
513
- try {
514
- const pid = parseInt(fs.readFileSync(PID_FILE, 'utf8').trim(), 10);
515
- process.kill(pid, 'SIGTERM');
516
- console.log(` ${c.green('OK')} Stopped running server (PID ${pid})`);
517
- } catch { /* ignore */ }
518
- }
519
-
520
- // 2. Remove slash commands
521
- const commandsDest = path.join(os.homedir(), '.claude', 'commands');
522
- const cmdsRemoved = [];
523
- if (fs.existsSync(commandsDest)) {
524
- const files = fs.readdirSync(commandsDest).filter(f => f.startsWith('upfynai'));
525
- for (const file of files) {
526
- fs.unlinkSync(path.join(commandsDest, file));
527
- cmdsRemoved.push(file);
528
- }
529
- }
530
- if (cmdsRemoved.length > 0) {
531
- console.log(` ${c.green('OK')} Removed ${cmdsRemoved.length} slash commands`);
532
- }
533
-
534
- // 3. Remove config directory (~/.upfynai/)
535
- if (fs.existsSync(CONFIG_DIR)) {
536
- fs.rmSync(CONFIG_DIR, { recursive: true, force: true });
537
- console.log(` ${c.green('OK')} Removed config directory: ${c.dim(CONFIG_DIR)}`);
538
- }
539
-
540
- // 4. Remove local database (in install dir)
541
- const dbPath = path.join(__dirname, 'database', 'auth.db');
542
- const dbFiles = [dbPath, dbPath + '-wal', dbPath + '-shm'];
543
- for (const f of dbFiles) {
544
- if (fs.existsSync(f)) {
545
- fs.unlinkSync(f);
546
- }
547
- }
548
- if (fs.existsSync(dbPath + '-wal') === false) {
549
- console.log(` ${c.green('OK')} Removed local database`);
550
- }
551
-
552
- console.log('');
553
- console.log(` ${c.bBright('Almost done!')} Run this to finish:`);
554
- console.log(` ${c.bright('npm uninstall -g upfynai-code')}`);
555
- console.log('');
556
- }
557
-
558
- // Reset: clear database only
559
- function resetApp() {
560
- console.log(`\n ${c.bBright('Upfyn-Code — Reset')}`);
561
- console.log(` ${c.dark('='.repeat(40))}\n`);
562
-
563
- const dbPath = getDatabasePath();
564
- const dbFiles = [dbPath, dbPath + '-wal', dbPath + '-shm'];
565
- let removed = false;
566
- for (const f of dbFiles) {
567
- if (fs.existsSync(f)) {
568
- fs.unlinkSync(f);
569
- removed = true;
570
- }
571
- }
572
-
573
- if (removed) {
574
- console.log(` ${c.green('OK')} Database cleared: ${c.dim(dbPath)}`);
575
- console.log(` ${c.dim('A fresh database will be created on next server start.')}\n`);
576
- } else {
577
- console.log(` ${c.yellow('!')} No database found at ${c.dim(dbPath)}\n`);
578
- }
579
- }
580
-
581
- // Start the server (self-hosted local mode)
582
- async function startServer() {
583
- // Check for updates silently on startup
584
- checkForUpdates(true);
585
-
586
- const port = process.env.PORT || '3001';
587
-
588
- // Auto-detect local mode — set IS_PLATFORM flag
589
- if (!process.env.RAILWAY_ENVIRONMENT && !process.env.VERCEL && !process.env.FORCE_HOSTED_MODE) {
590
- process.env.VITE_IS_PLATFORM = 'true';
591
- }
592
-
593
- // Write PID file so `uc stop` can kill this process
594
- writePidFile();
595
- process.on('exit', cleanupPidFile);
596
- process.on('SIGINT', () => { cleanupPidFile(); process.exit(0); });
597
- process.on('SIGTERM', () => { cleanupPidFile(); process.exit(0); });
598
-
599
- // Show server banner
600
- showServerBanner(port, packageJson.version);
601
-
602
- // Detect local agents
603
- const claudeBin = findClaudeBinary();
604
- if (claudeBin) {
605
- console.log(` ${c.green('OK')} Claude Code detected: ${c.bright(claudeBin)}`);
606
- } else {
607
- console.log(` ${c.yellow('!')} Claude Code not found. Install: ${c.bright('npm i -g @anthropic-ai/claude-code')}`);
608
- }
609
- console.log('');
610
-
611
- // Import and run the server
612
- await import('./index.js');
613
-
614
- // Auto-open browser after server starts (local mode only)
615
- if (!process.env.RAILWAY_ENVIRONMENT && !process.env.VERCEL) {
616
- const url = `http://localhost:${port}`;
617
- setTimeout(() => {
618
- try {
619
- const openCmd = process.platform === 'win32' ? 'start'
620
- : process.platform === 'darwin' ? 'open'
621
- : 'xdg-open';
622
- execSync(`${openCmd} ${url}`, { stdio: 'ignore' });
623
- console.log(` ${c.green('OK')} Opened ${c.cyan(url)} in browser\n`);
624
- } catch {
625
- console.log(` ${c.dim('Open in browser:')} ${c.cyan(url)}\n`);
626
- }
627
- }, 1500);
628
- }
629
- }
630
-
631
- // Parse CLI arguments
632
- function parseArgs(args) {
633
- const parsed = { command: null, options: {} };
634
-
635
- for (let i = 0; i < args.length; i++) {
636
- const arg = args[i];
637
-
638
- if (arg === '--port' || arg === '-p') {
639
- parsed.options.port = args[++i];
640
- } else if (arg.startsWith('--port=')) {
641
- parsed.options.port = arg.split('=')[1];
642
- } else if (arg === '--database-path') {
643
- parsed.options.databasePath = args[++i];
644
- } else if (arg.startsWith('--database-path=')) {
645
- parsed.options.databasePath = arg.split('=')[1];
646
- } else if (arg === '--server') {
647
- parsed.options.server = args[++i];
648
- } else if (arg.startsWith('--server=')) {
649
- parsed.options.server = arg.split('=')[1];
650
- } else if (arg === '--key') {
651
- parsed.options.key = args[++i];
652
- } else if (arg.startsWith('--key=')) {
653
- parsed.options.key = arg.split('=')[1];
654
- } else if (arg === '--api-key') {
655
- parsed.options.apiKey = args[++i];
656
- } else if (arg.startsWith('--api-key=')) {
657
- parsed.options.apiKey = arg.split('=')[1];
658
- } else if (arg === '--clear-api-key') {
659
- parsed.options.clearApiKey = true;
660
- } else if (arg === '--help' || arg === '-h') {
661
- parsed.command = 'help';
662
- } else if (arg === '--version' || arg === '-v') {
663
- parsed.command = 'version';
664
- } else if (!arg.startsWith('-') && !parsed.command) {
665
- parsed.command = arg;
666
- }
667
- }
668
-
669
- // Default command: launch interactive
670
- if (!parsed.command) {
671
- parsed.command = 'launch';
672
- }
673
-
674
- return parsed;
675
- }
676
-
677
- // Main CLI handler
678
- async function main() {
679
- const args = process.argv.slice(2);
680
- const { command, options } = parseArgs(args);
681
-
682
- // Apply CLI options to environment variables
683
- if (options.port) {
684
- process.env.PORT = options.port;
685
- }
686
- if (options.databasePath) {
687
- process.env.DATABASE_PATH = options.databasePath;
688
- }
689
-
690
- switch (command) {
691
- case 'launch':
692
- await launchInteractive();
693
- break;
694
- case 'start':
695
- await startServer();
696
- break;
697
- case 'status':
698
- case 'info':
699
- showStatus();
700
- break;
701
- case 'help':
702
- case '-h':
703
- case '--help':
704
- showHelp();
705
- break;
706
- case 'version':
707
- case '-v':
708
- case '--version':
709
- showVersion();
710
- break;
711
- case 'update':
712
- await updatePackage();
713
- break;
714
- case 'config':
715
- handleConfig(options);
716
- break;
717
- case 'install-commands':
718
- await installCommands();
719
- break;
720
- case 'uninstall-commands':
721
- await uninstallCommands();
722
- break;
723
- case 'stop':
724
- stopServer();
725
- break;
726
- case 'uninstall':
727
- uninstallApp();
728
- break;
729
- case 'reset':
730
- resetApp();
731
- break;
732
- case 'connect': {
733
- const { connectToServer } = await import('./relay-client.js');
734
- await connectToServer({
735
- server: options.server || args[1],
736
- key: options.key || args[2],
737
- });
738
- break;
739
- }
740
- default:
741
- console.error(`\n ${c.red('FAIL')} Unknown command: ${command}`);
742
- console.log(` Run ${c.bright('"uc help"')} for usage information.\n`);
743
- process.exit(1);
744
- }
745
- }
746
-
747
- // Run the CLI
748
- main().catch(error => {
749
- console.error(`\n ${c.red('FAIL')} Error: ${error.message}`);
750
- process.exit(1);
751
- });