upfynai-code 3.0.3 → 3.1.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 (243) hide show
  1. package/README.md +66 -91
  2. package/bin/cli.js +191 -0
  3. package/{client/dist → dist/client}/api-docs.html +838 -838
  4. package/{client/dist/assets/AppContent-Bvg0CPCO.js → dist/client/assets/AppContent-BofJquUs.js} +43 -43
  5. package/dist/client/assets/BrowserPanel-CSvD4jOX.js +2 -0
  6. package/dist/client/assets/CanvasFullScreen-onRfarpc.js +1 -0
  7. package/dist/client/assets/CanvasWorkspace-DvGKdL-k.js +259 -0
  8. package/dist/client/assets/DashboardPanel-DqAHbXDO.js +1 -0
  9. package/dist/client/assets/FileTree-BE0h-9M9.js +1 -0
  10. package/{client/dist/assets/GitPanel-RtyZUIWS.js → dist/client/assets/GitPanel-DdeJ0bp5.js} +2 -2
  11. package/{client/dist/assets/LoginModal-BWep8a6g.js → dist/client/assets/LoginModal-BP0pCTrH.js} +3 -3
  12. package/{client/dist/assets/MarkdownPreview-DHmk3qzu.js → dist/client/assets/MarkdownPreview-CESjI261.js} +1 -1
  13. package/dist/client/assets/MermaidBlock-D0rfEhrT.js +2 -0
  14. package/dist/client/assets/Onboarding-B2zQy-_6.js +1 -0
  15. package/dist/client/assets/SetupForm-Be7-WBe-.js +1 -0
  16. package/dist/client/assets/WorkflowsPanel-CusLbVJ6.js +1 -0
  17. package/{client/dist/assets/index-C5ptjuTl.js → dist/client/assets/index-BQy15irW.js} +25 -25
  18. package/dist/client/assets/index-CS0fDqEC.js +1 -0
  19. package/dist/client/assets/index-DYLSCCCp.css +1 -0
  20. package/dist/client/assets/vendor-canvas-QWTduIvM.js +23 -0
  21. package/{client/dist/assets/vendor-codemirror-CbtmxxaB.js → dist/client/assets/vendor-codemirror-D2ALgpaX.js} +1 -1
  22. package/{client/dist/assets/vendor-icons-BaD0x9SL.js → dist/client/assets/vendor-icons-kix3Gb31.js} +178 -138
  23. package/{client/dist/assets/vendor-mermaid-CH7SGc99.js → dist/client/assets/vendor-mermaid-CS3J4_Bz.js} +329 -326
  24. package/{client/dist/assets/vendor-syntax-DuHI9Ok6.js → dist/client/assets/vendor-syntax-LS_Nt30I.js} +1 -1
  25. package/{client/dist → dist/client}/clear-cache.html +85 -85
  26. package/dist/client/favicon.png +0 -0
  27. package/dist/client/favicon.svg +15 -0
  28. package/{client/dist → dist/client}/index.html +17 -17
  29. package/{client/dist → dist/client}/manifest.json +15 -15
  30. package/{client/dist → dist/client}/mcp-docs.html +108 -108
  31. package/{client/dist → dist/client}/offline.html +84 -84
  32. package/{client/dist → dist/client}/sw.js +82 -82
  33. package/package.json +55 -104
  34. package/scripts/postinstall.js +9 -0
  35. package/scripts/prepublish.js +77 -0
  36. package/src/animation.js +228 -0
  37. package/src/auth.js +142 -0
  38. package/src/config.js +40 -0
  39. package/src/connect.js +416 -0
  40. package/src/launch.js +81 -0
  41. package/src/mcp.js +57 -0
  42. package/src/permissions.js +140 -0
  43. package/src/persistent-shell.js +261 -0
  44. package/src/server.js +54 -0
  45. package/client/dist/assets/CanvasFullScreen-BdiJ35aq.js +0 -1
  46. package/client/dist/assets/CanvasWorkspace-Bk9R9_e0.js +0 -163
  47. package/client/dist/assets/DashboardPanel-CblJfTGi.js +0 -1
  48. package/client/dist/assets/FileTree-BDUnBheV.js +0 -1
  49. package/client/dist/assets/MermaidBlock-BuBc_G-F.js +0 -2
  50. package/client/dist/assets/Onboarding-Drnlt75a.js +0 -1
  51. package/client/dist/assets/SetupForm-CtCKitZG.js +0 -1
  52. package/client/dist/assets/WorkflowsPanel-B2mIXDvD.js +0 -1
  53. package/client/dist/assets/index-BFuqS0tY.css +0 -1
  54. package/client/dist/assets/vendor-canvas-D39yWul6.js +0 -49
  55. package/client/dist/favicon.png +0 -0
  56. package/client/dist/favicon.svg +0 -5
  57. package/commands/upfynai-connect.md +0 -59
  58. package/commands/upfynai-disconnect.md +0 -31
  59. package/commands/upfynai-doctor.md +0 -99
  60. package/commands/upfynai-export.md +0 -49
  61. package/commands/upfynai-local.md +0 -82
  62. package/commands/upfynai-status.md +0 -75
  63. package/commands/upfynai-stop.md +0 -49
  64. package/commands/upfynai-uninstall.md +0 -58
  65. package/commands/upfynai.md +0 -69
  66. package/scripts/build-client.js +0 -17
  67. package/scripts/fix-node-pty.js +0 -67
  68. package/scripts/install-commands.js +0 -78
  69. package/server/agent-loop.js +0 -242
  70. package/server/auto-compact.js +0 -99
  71. package/server/claude-sdk.js +0 -797
  72. package/server/cli-ui.js +0 -798
  73. package/server/cli.js +0 -751
  74. package/server/constants/config.js +0 -31
  75. package/server/cursor-cli.js +0 -270
  76. package/server/database/auth.db +0 -0
  77. package/server/database/db.js +0 -1451
  78. package/server/database/init.sql +0 -70
  79. package/server/index.js +0 -3814
  80. package/server/load-env.js +0 -26
  81. package/server/mcp-server.js +0 -621
  82. package/server/middleware/auth.js +0 -181
  83. package/server/middleware/relayHelpers.js +0 -44
  84. package/server/middleware/sandboxRouter.js +0 -174
  85. package/server/openai-codex.js +0 -403
  86. package/server/openrouter.js +0 -137
  87. package/server/projects.js +0 -1807
  88. package/server/provider-factory.js +0 -174
  89. package/server/relay-client.js +0 -390
  90. package/server/routes/agent.js +0 -1234
  91. package/server/routes/auth.js +0 -559
  92. package/server/routes/canvas.js +0 -53
  93. package/server/routes/cli-auth.js +0 -263
  94. package/server/routes/codex.js +0 -396
  95. package/server/routes/commands.js +0 -707
  96. package/server/routes/composio.js +0 -176
  97. package/server/routes/cursor.js +0 -770
  98. package/server/routes/dashboard.js +0 -295
  99. package/server/routes/git.js +0 -1208
  100. package/server/routes/keys.js +0 -34
  101. package/server/routes/mcp-utils.js +0 -48
  102. package/server/routes/mcp.js +0 -661
  103. package/server/routes/payments.js +0 -227
  104. package/server/routes/projects.js +0 -655
  105. package/server/routes/sessions.js +0 -146
  106. package/server/routes/settings.js +0 -261
  107. package/server/routes/taskmaster.js +0 -1928
  108. package/server/routes/user.js +0 -106
  109. package/server/routes/vapi-chat.js +0 -624
  110. package/server/routes/voice.js +0 -235
  111. package/server/routes/webhooks.js +0 -166
  112. package/server/routes/workflows.js +0 -312
  113. package/server/sandbox.js +0 -120
  114. package/server/services/composio.js +0 -204
  115. package/server/services/sessionRegistry.js +0 -139
  116. package/server/services/whisperService.js +0 -84
  117. package/server/services/workflowScheduler.js +0 -211
  118. package/server/tests/relay-flow.test.js +0 -570
  119. package/server/tests/sessions.test.js +0 -259
  120. package/server/utils/commandParser.js +0 -303
  121. package/server/utils/email.js +0 -66
  122. package/server/utils/gitConfig.js +0 -24
  123. package/server/utils/mcp-detector.js +0 -198
  124. package/server/utils/taskmaster-websocket.js +0 -129
  125. package/shared/integrationCatalog.d.ts +0 -12
  126. package/shared/integrationCatalog.js +0 -172
  127. package/shared/modelConstants.js +0 -96
  128. /package/{shared → dist}/agents/claude.js +0 -0
  129. /package/{shared → dist}/agents/codex.js +0 -0
  130. /package/{shared → dist}/agents/cursor.js +0 -0
  131. /package/{shared → dist}/agents/detect.js +0 -0
  132. /package/{shared → dist}/agents/exec.js +0 -0
  133. /package/{shared → dist}/agents/files.js +0 -0
  134. /package/{shared → dist}/agents/git.js +0 -0
  135. /package/{shared → dist}/agents/gitagent.js +0 -0
  136. /package/{shared → dist}/agents/index.js +0 -0
  137. /package/{shared → dist}/agents/shell.js +0 -0
  138. /package/{shared → dist}/agents/utils.js +0 -0
  139. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  140. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  141. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  142. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  143. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  144. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  145. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  146. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  147. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  148. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  149. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  150. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  151. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  152. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  153. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  154. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  155. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  156. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  157. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  158. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  159. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  160. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  161. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  162. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  163. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  164. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  165. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  166. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  167. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  168. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  169. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  170. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  171. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  172. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  173. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  174. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  175. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  176. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  177. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  178. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  179. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  180. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  181. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  182. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  183. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  184. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  185. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  186. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  187. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  188. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  189. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  190. /package/{client/dist → dist/client}/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  191. /package/{client/dist → dist/client}/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  192. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  193. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  194. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  195. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  196. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  197. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  198. /package/{client/dist → dist/client}/assets/PreviewPanel-CqCa92Tf.js +0 -0
  199. /package/{client/dist → dist/client}/assets/pdf-CE_K4jFx.js +0 -0
  200. /package/{client/dist → dist/client}/assets/vendor-canvas-BZV40eAE.css +0 -0
  201. /package/{client/dist → dist/client}/assets/vendor-diff-DNQpbhrT.js +0 -0
  202. /package/{client/dist → dist/client}/assets/vendor-i18n-DCFGyhQR.js +0 -0
  203. /package/{client/dist → dist/client}/assets/vendor-markdown-CimbIo6Y.js +0 -0
  204. /package/{client/dist → dist/client}/assets/vendor-react-96lCPsRK.js +0 -0
  205. /package/{client/dist → dist/client}/assets/vendor-xterm-CZq1hqo1.js +0 -0
  206. /package/{client/dist → dist/client}/assets/vendor-xterm-qxJ8_QYu.css +0 -0
  207. /package/{client/dist → dist/client}/convert-icons.md +0 -0
  208. /package/{client/dist → dist/client}/generate-icons.js +0 -0
  209. /package/{client/dist → dist/client}/icons/claude-ai-icon.svg +0 -0
  210. /package/{client/dist → dist/client}/icons/codex-white.svg +0 -0
  211. /package/{client/dist → dist/client}/icons/codex.svg +0 -0
  212. /package/{client/dist → dist/client}/icons/cursor-white.svg +0 -0
  213. /package/{client/dist → dist/client}/icons/cursor.svg +0 -0
  214. /package/{client/dist → dist/client}/icons/icon-128x128.png +0 -0
  215. /package/{client/dist → dist/client}/icons/icon-128x128.svg +0 -0
  216. /package/{client/dist → dist/client}/icons/icon-144x144.png +0 -0
  217. /package/{client/dist → dist/client}/icons/icon-144x144.svg +0 -0
  218. /package/{client/dist → dist/client}/icons/icon-152x152.png +0 -0
  219. /package/{client/dist → dist/client}/icons/icon-152x152.svg +0 -0
  220. /package/{client/dist → dist/client}/icons/icon-192x192.png +0 -0
  221. /package/{client/dist → dist/client}/icons/icon-192x192.svg +0 -0
  222. /package/{client/dist → dist/client}/icons/icon-384x384.png +0 -0
  223. /package/{client/dist → dist/client}/icons/icon-384x384.svg +0 -0
  224. /package/{client/dist → dist/client}/icons/icon-512x512.png +0 -0
  225. /package/{client/dist → dist/client}/icons/icon-512x512.svg +0 -0
  226. /package/{client/dist → dist/client}/icons/icon-72x72.png +0 -0
  227. /package/{client/dist → dist/client}/icons/icon-72x72.svg +0 -0
  228. /package/{client/dist → dist/client}/icons/icon-96x96.png +0 -0
  229. /package/{client/dist → dist/client}/icons/icon-96x96.svg +0 -0
  230. /package/{client/dist → dist/client}/icons/icon-template.svg +0 -0
  231. /package/{client/dist → dist/client}/logo-128.png +0 -0
  232. /package/{client/dist → dist/client}/logo-256.png +0 -0
  233. /package/{client/dist → dist/client}/logo-32.png +0 -0
  234. /package/{client/dist → dist/client}/logo-512.png +0 -0
  235. /package/{client/dist → dist/client}/logo-64.png +0 -0
  236. /package/{client/dist → dist/client}/logo.svg +0 -0
  237. /package/{client/dist → dist/client}/screenshots/cli-selection.png +0 -0
  238. /package/{client/dist → dist/client}/screenshots/desktop-main.png +0 -0
  239. /package/{client/dist → dist/client}/screenshots/mobile-chat.png +0 -0
  240. /package/{client/dist → dist/client}/screenshots/tools-modal.png +0 -0
  241. /package/{shared → dist}/gitagent/index.js +0 -0
  242. /package/{shared → dist}/gitagent/parser.js +0 -0
  243. /package/{shared → dist}/gitagent/prompt-builder.js +0 -0
@@ -0,0 +1,228 @@
1
+ /**
2
+ * CLI spaceship-to-star animation for Upfyn-Code.
3
+ * Plays after install (postinstall) and before `uc connect` starts.
4
+ */
5
+
6
+ const STAR_FRAMES = ['✦', '✧', '✦', '★'];
7
+
8
+ // Spaceship frames (4 animation states)
9
+ const SHIP = [
10
+ ' ╱▏▔▔╲ ',
11
+ ' ╱ ▏══ ╲ ',
12
+ '╱ ▏▁▁ ╲ ',
13
+ ' ╱▏▔▔╲ ',
14
+ ];
15
+
16
+ // Simpler inline ship for the travel animation
17
+ const SHIP_R = [
18
+ ' ▄▄ ',
19
+ ' ◁━━██━━▷ ',
20
+ ' ▀▀ ',
21
+ ];
22
+
23
+ const SHIP_SMALL = '◁━━▶';
24
+ const SHIP_TRAVEL = '⟫⟫';
25
+ const EXHAUST_CHARS = ['░', '▒', '▓', '═', '~', '·'];
26
+
27
+ function sleep(ms) {
28
+ return new Promise(r => setTimeout(r, ms));
29
+ }
30
+
31
+ function clearLines(n) {
32
+ for (let i = 0; i < n; i++) {
33
+ process.stdout.write('\x1b[1A\x1b[2K');
34
+ }
35
+ }
36
+
37
+ function dim(s) { return `\x1b[2m${s}\x1b[0m`; }
38
+ function cyan(s) { return `\x1b[36m${s}\x1b[0m`; }
39
+ function yellow(s) { return `\x1b[33m${s}\x1b[0m`; }
40
+ function bold(s) { return `\x1b[1m${s}\x1b[0m`; }
41
+ function magenta(s) { return `\x1b[35m${s}\x1b[0m`; }
42
+ function white(s) { return `\x1b[97m${s}\x1b[0m`; }
43
+ function green(s) { return `\x1b[32m${s}\x1b[0m`; }
44
+ function blue(s) { return `\x1b[34m${s}\x1b[0m`; }
45
+
46
+ /**
47
+ * Generate a star field background line
48
+ */
49
+ function starFieldLine(width, density = 0.08, frame = 0) {
50
+ let line = '';
51
+ for (let i = 0; i < width; i++) {
52
+ if (Math.random() < density) {
53
+ const stars = ['.', '·', '∘', '°', '✧'];
54
+ const s = stars[Math.floor(Math.random() * stars.length)];
55
+ line += dim(s);
56
+ } else {
57
+ line += ' ';
58
+ }
59
+ }
60
+ return line;
61
+ }
62
+
63
+ /**
64
+ * Main spaceship-to-star animation
65
+ * @param {'install'|'connect'} mode
66
+ */
67
+ export async function playSpaceshipAnimation(mode = 'connect') {
68
+ const cols = Math.min(process.stdout.columns || 70, 80);
69
+ const totalFrames = 28;
70
+ const LINES = 11; // total lines we'll use
71
+
72
+ const starX = cols - 6;
73
+
74
+ // Phase 1: Launch sequence text
75
+ const tagline = mode === 'install'
76
+ ? 'Installation complete!'
77
+ : 'Launching relay bridge...';
78
+
79
+ console.log('');
80
+ console.log(dim(' ─'.repeat(Math.floor(cols / 3))));
81
+ console.log('');
82
+
83
+ // Phase 2: Spaceship travels across the screen toward a star
84
+ for (let frame = 0; frame < totalFrames; frame++) {
85
+ const progress = frame / (totalFrames - 1); // 0 → 1
86
+ const shipX = Math.floor(progress * (cols - 16)) + 2;
87
+
88
+ // Build exhaust trail
89
+ const exhaustLen = Math.min(shipX, Math.floor(progress * 20));
90
+ let exhaust = '';
91
+ for (let e = 0; e < exhaustLen; e++) {
92
+ const intensity = 1 - (e / exhaustLen);
93
+ if (intensity > 0.7) exhaust = '▓' + exhaust;
94
+ else if (intensity > 0.4) exhaust = '▒' + exhaust;
95
+ else if (intensity > 0.2) exhaust = '░' + exhaust;
96
+ else exhaust = '·' + exhaust;
97
+ }
98
+
99
+ // Star pulse
100
+ const starChar = STAR_FRAMES[frame % STAR_FRAMES.length];
101
+ const starGlow = progress > 0.7 ? yellow('✦ ') : '';
102
+
103
+ // Build the 5 display lines
104
+ const lines = [];
105
+
106
+ // Line 1: starfield
107
+ lines.push(' ' + starFieldLine(cols - 4, 0.05, frame));
108
+
109
+ // Line 2: top space
110
+ lines.push(' ' + starFieldLine(cols - 4, 0.03, frame));
111
+
112
+ // Line 3: ship row (main action)
113
+ let shipRow = '';
114
+ const beforeShip = Math.max(0, shipX - exhaustLen);
115
+ shipRow += ' '.repeat(beforeShip);
116
+ shipRow += dim(exhaust);
117
+ shipRow += cyan(' ◁━━▶');
118
+ // Fill to star position
119
+ const afterShip = Math.max(0, starX - shipX - 7);
120
+ // Dots between ship and star
121
+ let midSpace = '';
122
+ for (let d = 0; d < afterShip; d++) {
123
+ midSpace += Math.random() < 0.06 ? dim('·') : ' ';
124
+ }
125
+ shipRow += midSpace;
126
+ if (progress < 0.92) {
127
+ shipRow += starGlow + yellow(starChar);
128
+ } else {
129
+ shipRow += yellow('✦★✦');
130
+ }
131
+ lines.push(shipRow);
132
+
133
+ // Line 4: thrust glow
134
+ let thrustRow = ' '.repeat(Math.max(0, shipX + 1));
135
+ if (frame % 2 === 0) {
136
+ thrustRow += dim(magenta('~≈~'));
137
+ } else {
138
+ thrustRow += dim(magenta('≈~≈'));
139
+ }
140
+ lines.push(thrustRow);
141
+
142
+ // Line 5: starfield
143
+ lines.push(' ' + starFieldLine(cols - 4, 0.04, frame));
144
+
145
+ // Line 6: message (centered)
146
+ const msg = progress < 0.3
147
+ ? dim(` ${tagline}`)
148
+ : progress < 0.6
149
+ ? cyan(` ⟫ Navigating to the stars...`)
150
+ : progress < 0.9
151
+ ? magenta(` ⟫⟫ Almost there...`)
152
+ : green(` ★ ${mode === 'install' ? 'Ready for launch!' : 'Connection established!'}`);
153
+ lines.push(msg);
154
+
155
+ // Line 7: progress bar
156
+ const barWidth = cols - 10;
157
+ const filled = Math.floor(progress * barWidth);
158
+ const bar = ' ' + dim('[')
159
+ + cyan('█'.repeat(filled))
160
+ + dim('░'.repeat(barWidth - filled))
161
+ + dim(']')
162
+ + dim(` ${Math.floor(progress * 100)}%`);
163
+ lines.push(bar);
164
+
165
+ // Print
166
+ if (frame > 0) clearLines(lines.length);
167
+ for (const l of lines) console.log(l);
168
+
169
+ // Speed: start slow, middle fast, end slow
170
+ const delay = progress < 0.2 ? 120
171
+ : progress > 0.85 ? 150
172
+ : 60;
173
+ await sleep(delay);
174
+ }
175
+
176
+ // Phase 3: Final flash
177
+ await sleep(200);
178
+ clearLines(7);
179
+
180
+ // Arrival burst
181
+ const burstLines = [];
182
+ burstLines.push(' ' + starFieldLine(cols - 4, 0.06));
183
+ burstLines.push('');
184
+ burstLines.push(
185
+ ' '.repeat(Math.floor(cols / 2 - 12))
186
+ + yellow('· ✧ · ★ ')
187
+ + bold(white('UPFYN'))
188
+ + yellow(' ★ · ✧ ·')
189
+ );
190
+ burstLines.push('');
191
+
192
+ if (mode === 'install') {
193
+ burstLines.push(
194
+ ' '.repeat(Math.floor(cols / 2 - 20))
195
+ + green('✓ ') + bold('upfynai-code') + dim(' installed successfully')
196
+ );
197
+ burstLines.push('');
198
+ burstLines.push(dim(' Quick start:'));
199
+ burstLines.push(cyan(' uc login ') + dim('— authenticate'));
200
+ burstLines.push(cyan(' uc connect ') + dim('— bridge to cloud'));
201
+ burstLines.push(cyan(' uc --local ') + dim('— start local server'));
202
+ } else {
203
+ burstLines.push(
204
+ ' '.repeat(Math.floor(cols / 2 - 16))
205
+ + green('✓ ') + bold('Relay bridge activated')
206
+ );
207
+ }
208
+
209
+ burstLines.push('');
210
+ burstLines.push(dim(' ─'.repeat(Math.floor(cols / 3))));
211
+ burstLines.push('');
212
+
213
+ for (const l of burstLines) console.log(l);
214
+ }
215
+
216
+ /**
217
+ * Postinstall animation (shorter variant)
218
+ */
219
+ export async function playInstallAnimation() {
220
+ return playSpaceshipAnimation('install');
221
+ }
222
+
223
+ /**
224
+ * Connect animation
225
+ */
226
+ export async function playConnectAnimation() {
227
+ return playSpaceshipAnimation('connect');
228
+ }
package/src/auth.js ADDED
@@ -0,0 +1,142 @@
1
+ import prompts from 'prompts';
2
+ import chalk from 'chalk';
3
+ import { readConfig, writeConfig, clearConfig, displayUrl } from './config.js';
4
+
5
+ async function apiCall(path, options = {}) {
6
+ const config = readConfig();
7
+ const url = `${config.serverUrl}${path}`;
8
+ const res = await fetch(url, {
9
+ ...options,
10
+ headers: {
11
+ 'Content-Type': 'application/json',
12
+ ...(options.headers || {}),
13
+ },
14
+ });
15
+ return res;
16
+ }
17
+
18
+ export function getToken() {
19
+ const config = readConfig();
20
+ return config.token || null;
21
+ }
22
+
23
+ export async function validateToken() {
24
+ const token = getToken();
25
+ if (!token) return null;
26
+
27
+ try {
28
+ const res = await apiCall('/api/auth/user', {
29
+ headers: { Authorization: `Bearer ${token}` },
30
+ });
31
+ if (!res.ok) return null;
32
+ const data = await res.json();
33
+ return data.user || null;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ export async function login(options = {}) {
40
+ // Allow --server flag to override the server URL
41
+ if (options.server) {
42
+ writeConfig({ serverUrl: options.server.replace(/\/+$/, '') });
43
+ }
44
+
45
+ console.log(chalk.bold('\n Upfyn Code — Login\n'));
46
+
47
+ const response = await prompts([
48
+ {
49
+ type: 'text',
50
+ name: 'username',
51
+ message: 'Username',
52
+ validate: v => (v.trim() ? true : 'Username is required'),
53
+ },
54
+ {
55
+ type: 'password',
56
+ name: 'password',
57
+ message: 'Password',
58
+ validate: v => (v ? true : 'Password is required'),
59
+ },
60
+ ], {
61
+ onCancel: () => {
62
+ console.log(chalk.dim('\n Login cancelled.\n'));
63
+ process.exit(0);
64
+ },
65
+ });
66
+
67
+ const { username, password } = response;
68
+
69
+ try {
70
+ const res = await apiCall('/api/auth/login', {
71
+ method: 'POST',
72
+ body: JSON.stringify({ username: username.trim(), password }),
73
+ });
74
+
75
+ const data = await res.json();
76
+
77
+ if (!res.ok) {
78
+ console.log(chalk.red(`\n Login failed: ${data.error || 'Unknown error'}\n`));
79
+ process.exit(1);
80
+ }
81
+
82
+ writeConfig({
83
+ token: data.token,
84
+ user: data.user,
85
+ });
86
+
87
+ const name = data.user.first_name || data.user.username;
88
+ console.log(chalk.green(`\n Logged in as ${chalk.bold(name)}!`));
89
+
90
+ // Auto-fetch and save relay token for one-command connect
91
+ try {
92
+ const config = readConfig();
93
+ const tokenRes = await fetch(`${config.serverUrl}/api/auth/connect-token`, {
94
+ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${data.token}` },
95
+ });
96
+ if (tokenRes.ok) {
97
+ const tokenData = await tokenRes.json();
98
+ if (tokenData.token) {
99
+ writeConfig({ relayKey: tokenData.token });
100
+ console.log(chalk.dim(' Relay token saved.'));
101
+ console.log(chalk.cyan(`\n Run ${chalk.bold('uc web connect')} to bridge your machine to the web UI.\n`));
102
+ }
103
+ }
104
+ } catch { /* best-effort — relay token fetch is optional */ }
105
+
106
+ if (!readConfig().relayKey) {
107
+ console.log('');
108
+ }
109
+ } catch (err) {
110
+ const config = readConfig();
111
+ console.log(chalk.red(`\n Connection error. Could not reach ${displayUrl(config.serverUrl)}.`));
112
+ console.log(chalk.dim(' Check your network and try again.\n'));
113
+ process.exit(1);
114
+ }
115
+ }
116
+
117
+ export async function logout() {
118
+ clearConfig();
119
+ console.log(chalk.green('\n Logged out. Credentials cleared.\n'));
120
+ }
121
+
122
+ export async function status() {
123
+ const config = readConfig();
124
+
125
+ if (!config.token) {
126
+ console.log(chalk.yellow('\n Not logged in. Run `uc login` to authenticate.\n'));
127
+ return;
128
+ }
129
+
130
+ console.log(chalk.dim('\n Checking session...'));
131
+ const user = await validateToken();
132
+
133
+ if (!user) {
134
+ console.log(chalk.yellow(' Session expired. Run `uc login` to re-authenticate.\n'));
135
+ return;
136
+ }
137
+
138
+ const name = user.first_name || user.username;
139
+ console.log(chalk.bold(` Logged in as: ${chalk.cyan(name)} (${chalk.dim(user.username)})`));
140
+ console.log(chalk.dim(` Server: ${displayUrl(config.serverUrl)}`));
141
+ console.log(chalk.dim(` Local port: ${config.localPort}\n`));
142
+ }
package/src/config.js ADDED
@@ -0,0 +1,40 @@
1
+ import { readFileSync, writeFileSync, mkdirSync } from 'fs';
2
+ import { homedir } from 'os';
3
+ import { join, dirname } from 'path';
4
+
5
+ const CONFIG_PATH = join(homedir(), '.upfynrc');
6
+
7
+ const DEFAULTS = {
8
+ serverUrl: 'https://upfynai-code-production.up.railway.app',
9
+ localPort: 4200,
10
+ };
11
+
12
+ export function readConfig() {
13
+ try {
14
+ const raw = readFileSync(CONFIG_PATH, 'utf-8');
15
+ return { ...DEFAULTS, ...JSON.parse(raw) };
16
+ } catch {
17
+ return { ...DEFAULTS };
18
+ }
19
+ }
20
+
21
+ export function writeConfig(data) {
22
+ const existing = readConfig();
23
+ const merged = { ...existing, ...data };
24
+ mkdirSync(dirname(CONFIG_PATH), { recursive: true });
25
+ writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
26
+ return merged;
27
+ }
28
+
29
+ export function clearConfig() {
30
+ writeFileSync(CONFIG_PATH, JSON.stringify(DEFAULTS, null, 2) + '\n', 'utf-8');
31
+ }
32
+
33
+ /** Display-friendly server label — masks the internal URL */
34
+ export function displayUrl(url) {
35
+ if (!url || url === DEFAULTS.serverUrl) return 'Upfyn Cloud';
36
+ // Custom server — show the hostname only
37
+ try { return new URL(url).host; } catch { return url; }
38
+ }
39
+
40
+ export { CONFIG_PATH, DEFAULTS };