upfynai-code 2.3.0 → 2.4.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 (158) hide show
  1. package/client/dist/assets/AppContent-DTZ2FbvM.js +513 -0
  2. package/client/dist/assets/CanvasPanel-DlTW6Jh6.js +6 -0
  3. package/client/dist/assets/LoginModal-CWoFm0au.js +19 -0
  4. package/client/dist/assets/MarkdownPreview-CYdvwJaV.js +1 -0
  5. package/client/dist/assets/{Onboarding-Coxo6mFA.js → Onboarding-CtIoXiTp.js} +1 -1
  6. package/client/dist/assets/{SetupForm-BzYOsbji.js → SetupForm-B4p8im5O.js} +1 -1
  7. package/client/dist/assets/{ar-SA-G6X2FPQ2-Bmw2-hDt.js → ar-SA-G6X2FPQ2-2gfmdvHk.js} +1 -1
  8. package/client/dist/assets/{arc-BMqY7_Ci.js → arc-DCZSHhoJ.js} +1 -1
  9. package/client/dist/assets/{az-AZ-76LH7QW2-Dh1le_qs.js → az-AZ-76LH7QW2-CDdeucRZ.js} +1 -1
  10. package/client/dist/assets/{bg-BG-XCXSNQG7-Cbav8Z9z.js → bg-BG-XCXSNQG7-D6__XtOK.js} +1 -1
  11. package/client/dist/assets/{blockDiagram-38ab4fdb-ChHJxsXw.js → blockDiagram-38ab4fdb-Cfbaeyp6.js} +3 -3
  12. package/client/dist/assets/{bn-BD-2XOGV67Q-DCNjOaWz.js → bn-BD-2XOGV67Q-DHNJw3OG.js} +1 -1
  13. package/client/dist/assets/{c4Diagram-3d4e48cf-b8Xue4Z6.js → c4Diagram-3d4e48cf-BBCnjOTy.js} +1 -1
  14. package/client/dist/assets/{ca-ES-6MX7JW3Y-Dl_vM7NS.js → ca-ES-6MX7JW3Y-r5g4o3zQ.js} +1 -1
  15. package/client/dist/assets/channel-O3ovC0x9.js +1 -0
  16. package/client/dist/assets/{classDiagram-70f12bd4-BheP7Ggo.js → classDiagram-70f12bd4-D0lhAcxU.js} +1 -1
  17. package/client/dist/assets/classDiagram-v2-f2320105-BuwUsF3F.js +2 -0
  18. package/client/dist/assets/clone-BG9u7vLi.js +1 -0
  19. package/client/dist/assets/{createText-2e5e7dd3-_n4jI_fO.js → createText-2e5e7dd3-B8jCDmF_.js} +1 -1
  20. package/client/dist/assets/{cs-CZ-2BRQDIVT-ftsKDdz4.js → cs-CZ-2BRQDIVT-p08jRLRC.js} +1 -1
  21. package/client/dist/assets/{da-DK-5WZEPLOC-DAjdwGRO.js → da-DK-5WZEPLOC-CnhOImFf.js} +1 -1
  22. package/client/dist/assets/{de-DE-XR44H4JA-BJXczHGT.js → de-DE-XR44H4JA-BunSXZ-Y.js} +1 -1
  23. package/client/dist/assets/{edges-e0da2a9e-CfPZr4YM.js → edges-e0da2a9e-CGBBhG8k.js} +2 -2
  24. package/client/dist/assets/{el-GR-BZB4AONW-DW2p_uy7.js → el-GR-BZB4AONW-D4wv1oIz.js} +1 -1
  25. package/client/dist/assets/{erDiagram-9861fffd-CF33V-Of.js → erDiagram-9861fffd-CYaF3q1I.js} +1 -1
  26. package/client/dist/assets/{es-ES-U4NZUMDT-DLOIGnrl.js → es-ES-U4NZUMDT-CGeTKXgd.js} +1 -1
  27. package/client/dist/assets/{eu-ES-A7QVB2H4-LJXbf89m.js → eu-ES-A7QVB2H4-Cayx1TxR.js} +1 -1
  28. package/client/dist/assets/{fa-IR-HGAKTJCU-Dvx65fgW.js → fa-IR-HGAKTJCU-CmUg8pmw.js} +1 -1
  29. package/client/dist/assets/{fi-FI-Z5N7JZ37-EoL65BQh.js → fi-FI-Z5N7JZ37-xvHcPhsU.js} +1 -1
  30. package/client/dist/assets/{flowDb-956e92f1-HgoXVy2H.js → flowDb-956e92f1-C-_LFz70.js} +3 -3
  31. package/client/dist/assets/flowDiagram-66a62f08-C1sHdSjn.js +4 -0
  32. package/client/dist/assets/flowDiagram-v2-96b9c2cf-Cd0Iascd.js +1 -0
  33. package/client/dist/assets/{flowchart-elk-definition-4a651766-DJbI2dpv.js → flowchart-elk-definition-4a651766-CNGfpudb.js} +7 -7
  34. package/client/dist/assets/{fr-FR-RHASNOE6-DNk_jdDs.js → fr-FR-RHASNOE6-DBoHEcNj.js} +1 -1
  35. package/client/dist/assets/{ganttDiagram-c361ad54-2XX670FU.js → ganttDiagram-c361ad54-B8HJQqjt.js} +1 -1
  36. package/client/dist/assets/{gitGraphDiagram-72cf32ee-CcUfruAo.js → gitGraphDiagram-72cf32ee-DojCDvlS.js} +1 -1
  37. package/client/dist/assets/{gl-ES-HMX3MZ6V-dxzFjZlG.js → gl-ES-HMX3MZ6V-p6hrn2cN.js} +1 -1
  38. package/client/dist/assets/{graph-BSbiMSBC.js → graph-DXM7lcy1.js} +1 -1
  39. package/client/dist/assets/{he-IL-6SHJWFNN-Cogsfdt1.js → he-IL-6SHJWFNN-y2jEX6-0.js} +1 -1
  40. package/client/dist/assets/{hi-IN-IWLTKZ5I-L6wbgi4F.js → hi-IN-IWLTKZ5I-99pNfyWr.js} +1 -1
  41. package/client/dist/assets/{hu-HU-A5ZG7DT2-DSA6ZDsH.js → hu-HU-A5ZG7DT2-hygceGMS.js} +1 -1
  42. package/client/dist/assets/{id-ID-SAP4L64H-BK_vGGS6.js → id-ID-SAP4L64H-CyIqi1hv.js} +1 -1
  43. package/client/dist/assets/{image-blob-reduce.esm-BLtmMM_J.js → image-blob-reduce.esm-D6s-rqMO.js} +6 -1
  44. package/client/dist/assets/{index-3862675e-Bv32HUgT.js → index-3862675e-4idOQN2N.js} +1 -1
  45. package/client/dist/assets/{index-BPwf8Fw3.js → index-BGmwbRlb.js} +6 -6
  46. package/client/dist/assets/index-BHZfFT_V.js +97 -0
  47. package/client/dist/assets/{infoDiagram-f8f76790-w4mR4pxn.js → infoDiagram-f8f76790-CFLrHqtc.js} +1 -1
  48. package/client/dist/assets/{it-IT-JPQ66NNP-BLdHYMhn.js → it-IT-JPQ66NNP-DzVvVdQI.js} +1 -1
  49. package/client/dist/assets/{ja-JP-DBVTYXUO-B_vmexl_.js → ja-JP-DBVTYXUO-BI4fPexV.js} +1 -1
  50. package/client/dist/assets/{journeyDiagram-49397b02-D9nmO17e.js → journeyDiagram-49397b02-C3CFDo8z.js} +1 -1
  51. package/client/dist/assets/{kaa-6HZHGXH3-5s-3jl6F.js → kaa-6HZHGXH3-fwOleoQB.js} +1 -1
  52. package/client/dist/assets/{kab-KAB-ZGHBKWFO-2QaVDuSf.js → kab-KAB-ZGHBKWFO-DBI_ri48.js} +1 -1
  53. package/client/dist/assets/{kk-KZ-P5N5QNE5-CTC52Vbi.js → kk-KZ-P5N5QNE5-zpl7uvyF.js} +1 -1
  54. package/client/dist/assets/{km-KH-HSX4SM5Z-DxawH8UZ.js → km-KH-HSX4SM5Z-DOMFSres.js} +1 -1
  55. package/client/dist/assets/{ko-KR-MTYHY66A-CmosEM8_.js → ko-KR-MTYHY66A-tb08hXzd.js} +1 -1
  56. package/client/dist/assets/{ku-TR-6OUDTVRD-DbiLen4y.js → ku-TR-6OUDTVRD-DlIQCCY4.js} +1 -1
  57. package/client/dist/assets/{layout-jmt3H9tA.js → layout-B_11mCXA.js} +1 -1
  58. package/client/dist/assets/{line-JTlRayUJ.js → line-B-qmK_vI.js} +1 -1
  59. package/client/dist/assets/{linear-DJeB5p7x.js → linear-Ph6uuYcX.js} +1 -1
  60. package/client/dist/assets/{lt-LT-XHIRWOB4-CH15wrjA.js → lt-LT-XHIRWOB4--qWy24_Z.js} +1 -1
  61. package/client/dist/assets/{lv-LV-5QDEKY6T-dhgfPuCQ.js → lv-LV-5QDEKY6T-Bnd_1GDb.js} +1 -1
  62. package/client/dist/assets/mindmap-definition-fc14e90a-Do79tIc0.js +425 -0
  63. package/client/dist/assets/{mr-IN-CRQNXWMA-3Gi6iq7A.js → mr-IN-CRQNXWMA-BsV6HaD9.js} +1 -1
  64. package/client/dist/assets/{my-MM-5M5IBNSE-CpH4rdJj.js → my-MM-5M5IBNSE-kZQURVIi.js} +1 -1
  65. package/client/dist/assets/{nb-NO-T6EIAALU-Du6iiGql.js → nb-NO-T6EIAALU-Cvf9FdSF.js} +1 -1
  66. package/client/dist/assets/{nl-NL-IS3SIHDZ-BGvsd1MT.js → nl-NL-IS3SIHDZ-DA1yqpXw.js} +1 -1
  67. package/client/dist/assets/{nn-NO-6E72VCQL-B-odvJZW.js → nn-NO-6E72VCQL-89lm3vku.js} +1 -1
  68. package/client/dist/assets/{oc-FR-POXYY2M6-COC8xNjo.js → oc-FR-POXYY2M6-BsrjTJQh.js} +1 -1
  69. package/client/dist/assets/{pa-IN-N4M65BXN-CE21PUQH.js → pa-IN-N4M65BXN-CczefYaj.js} +1 -1
  70. package/client/dist/assets/pdf-CE_K4jFx.js +12 -0
  71. package/client/dist/assets/percentages-BXMCSKIN-Be6p9phi.js +207 -0
  72. package/client/dist/assets/pica-CQIY57Tf.js +7 -0
  73. package/client/dist/assets/{pieDiagram-8a3498a8-Cvfh7Qr5.js → pieDiagram-8a3498a8-CfblQHdm.js} +2 -2
  74. package/client/dist/assets/{pl-PL-T2D74RX3-D4xFVSoT.js → pl-PL-T2D74RX3-DdhH-zcK.js} +1 -1
  75. package/client/dist/assets/{pt-BR-5N22H2LF-CCq257gA.js → pt-BR-5N22H2LF-gpwlheL6.js} +1 -1
  76. package/client/dist/assets/{pt-PT-UZXXM6DQ-1l8gt5vA.js → pt-PT-UZXXM6DQ-Cs87vICi.js} +1 -1
  77. package/client/dist/assets/{quadrantDiagram-120e2f19-BA0js1aD.js → quadrantDiagram-120e2f19-CRMSamSP.js} +1 -1
  78. package/client/dist/assets/{requirementDiagram-deff3bca-B0QNFfIn.js → requirementDiagram-deff3bca-D3LBN016.js} +1 -1
  79. package/client/dist/assets/{ro-RO-JPDTUUEW-yosBW01E.js → ro-RO-JPDTUUEW-CWTSJ1Dt.js} +1 -1
  80. package/client/dist/assets/roundRect-0PYZxl1G.js +1 -0
  81. package/client/dist/assets/{ru-RU-B4JR7IUQ-8LkEJUix.js → ru-RU-B4JR7IUQ-Bq7aN2ep.js} +1 -1
  82. package/client/dist/assets/{sankeyDiagram-04a897e0-D4T9eCXn.js → sankeyDiagram-04a897e0-CsFqOQZN.js} +3 -3
  83. package/client/dist/assets/{sequenceDiagram-704730f1-CfBUTCrO.js → sequenceDiagram-704730f1-BRYXVDGX.js} +1 -1
  84. package/client/dist/assets/{si-LK-N5RQ5JYF-D8rjbqtd.js → si-LK-N5RQ5JYF-BBjcNYQh.js} +1 -1
  85. package/client/dist/assets/{sk-SK-C5VTKIMK-Bg14sAzN.js → sk-SK-C5VTKIMK-ByjKQzUb.js} +1 -1
  86. package/client/dist/assets/{sl-SI-NN7IZMDC-CMTib6Zs.js → sl-SI-NN7IZMDC-B8WCyMBU.js} +1 -1
  87. package/client/dist/assets/{stateDiagram-587899a1-BGgvmVSZ.js → stateDiagram-587899a1-BHoy9LtD.js} +1 -1
  88. package/client/dist/assets/{stateDiagram-v2-d93cdb3a-Qn3DpYuO.js → stateDiagram-v2-d93cdb3a-BvMUA6bS.js} +1 -1
  89. package/client/dist/assets/{styles-6aaf32cf-IdVZLPrD.js → styles-6aaf32cf-Dr-lfIOW.js} +2 -2
  90. package/client/dist/assets/{styles-9a916d00-BAC3L45X.js → styles-9a916d00-DS4wRpL7.js} +1 -1
  91. package/client/dist/assets/{styles-c10674c1-COhXxX8c.js → styles-c10674c1-nKRF6NrH.js} +1 -1
  92. package/client/dist/assets/{subset-shared.chunk-BWHnFai4.js → subset-shared.chunk-KT79s7KG.js} +64 -2
  93. package/client/dist/assets/subset-worker.chunk-BMx1eyv3.js +1 -0
  94. package/client/dist/assets/{sv-SE-XGPEYMSR-C1425rOF.js → sv-SE-XGPEYMSR-BiIPUVbv.js} +1 -1
  95. package/client/dist/assets/{svgDrawCommon-08f97a94-Cfk-fgnN.js → svgDrawCommon-08f97a94-C3uP9PYr.js} +1 -1
  96. package/client/dist/assets/{ta-IN-2NMHFXQM-BHHo1zpF.js → ta-IN-2NMHFXQM-Cidadso2.js} +1 -1
  97. package/client/dist/assets/{th-TH-HPSO5L25-CZVzm_WT.js → th-TH-HPSO5L25-CFNnJwSv.js} +1 -1
  98. package/client/dist/assets/{timeline-definition-85554ec2-VAvuJith.js → timeline-definition-85554ec2-BSsLsIgF.js} +1 -1
  99. package/client/dist/assets/{tr-TR-DEFEU3FU-DE1lclCq.js → tr-TR-DEFEU3FU-DaFcI-KL.js} +1 -1
  100. package/client/dist/assets/{uk-UA-QMV73CPH-D4lJZ85O.js → uk-UA-QMV73CPH-DkBW36St.js} +1 -1
  101. package/client/dist/assets/vendor-codemirror-langs-BH1ZcKHY.js +20 -0
  102. package/client/dist/assets/vendor-codemirror-rix45NST.js +16 -0
  103. package/client/dist/assets/vendor-i18n-DCFGyhQR.js +1 -0
  104. package/client/dist/assets/vendor-icons-Dh9m_Ydt.js +596 -0
  105. package/client/dist/assets/{vendor-markdown-CIVH08vJ.js → vendor-markdown-BXEi_H3G.js} +3 -3
  106. package/client/dist/assets/vendor-react-9mUTKBHH.js +67 -0
  107. package/client/dist/assets/{vendor-syntax-Djb62v3a.js → vendor-syntax-DnmwQQJF.js} +14 -7
  108. package/client/dist/assets/vendor-xterm-CZq1hqo1.js +66 -0
  109. package/client/dist/assets/vendor-xterm-qxJ8_QYu.css +32 -0
  110. package/client/dist/assets/{vi-VN-M7AON7JQ-Dgc_SShk.js → vi-VN-M7AON7JQ-KrtfxOzl.js} +1 -1
  111. package/client/dist/assets/{xychartDiagram-e933f94c-BeyVBJhb.js → xychartDiagram-e933f94c-CgNgZ4pp.js} +1 -1
  112. package/client/dist/assets/{zh-CN-LNUGB5OW-MH4Yh8in.js → zh-CN-LNUGB5OW-BQu12RoD.js} +1 -1
  113. package/client/dist/assets/{zh-HK-E62DVLB3-D4XHehjx.js → zh-HK-E62DVLB3-zx9CvERq.js} +1 -1
  114. package/client/dist/assets/{zh-TW-RAJ6MFWO--efj3evj.js → zh-TW-RAJ6MFWO-ffJWgVxn.js} +1 -1
  115. package/client/dist/index.html +128 -66
  116. package/client/dist/manifest.json +61 -15
  117. package/client/dist/sw.js +19 -55
  118. package/commands/upfynai-connect.md +31 -18
  119. package/commands/upfynai.md +45 -26
  120. package/package.json +1 -1
  121. package/server/cli-ui.js +320 -169
  122. package/server/cli.js +194 -21
  123. package/server/index.js +159 -107
  124. package/server/middleware/auth.js +9 -5
  125. package/server/openrouter.js +137 -0
  126. package/server/relay-client.js +104 -17
  127. package/server/routes/agent.js +54 -19
  128. package/server/routes/auth.js +23 -12
  129. package/server/routes/settings.js +91 -0
  130. package/shared/modelConstants.js +29 -0
  131. package/client/dist/assets/AppContent-CTSHQdyq.js +0 -513
  132. package/client/dist/assets/CanvasPanel-Cig0Mo9s.js +0 -6
  133. package/client/dist/assets/LoginModal-silya-zP.js +0 -11
  134. package/client/dist/assets/MarkdownPreview-B3c7OEj6.js +0 -1
  135. package/client/dist/assets/channel-CSnvHe_M.js +0 -1
  136. package/client/dist/assets/classDiagram-v2-f2320105-xtym7GEZ.js +0 -2
  137. package/client/dist/assets/clone-B75abXxS.js +0 -1
  138. package/client/dist/assets/flowDiagram-66a62f08-tffoET0H.js +0 -4
  139. package/client/dist/assets/flowDiagram-v2-96b9c2cf-Byc3JCHh.js +0 -1
  140. package/client/dist/assets/index-BnXuHrpJ.js +0 -523
  141. package/client/dist/assets/index-BwxNox94.css +0 -1
  142. package/client/dist/assets/index-D1urGMYu.js +0 -95
  143. package/client/dist/assets/mindmap-definition-fc14e90a-BOOrexmz.js +0 -415
  144. package/client/dist/assets/pdf-TYrZqVzP.js +0 -12
  145. package/client/dist/assets/percentages-BXMCSKIN-C9GT0OD3.js +0 -199
  146. package/client/dist/assets/pica-VkdyTzi8.js +0 -2
  147. package/client/dist/assets/roundRect-mAH3dD0p.js +0 -1
  148. package/client/dist/assets/subset-worker.chunk-C8QUSruZ.js +0 -1
  149. package/client/dist/assets/vendor-codemirror-BARtJV1V.js +0 -16
  150. package/client/dist/assets/vendor-codemirror-langs-52_y1wip.js +0 -20
  151. package/client/dist/assets/vendor-i18n-ByAl-gdx.js +0 -1
  152. package/client/dist/assets/vendor-icons-D33IkSIf.js +0 -1
  153. package/client/dist/assets/vendor-react-CHoMc7ka.js +0 -8
  154. package/client/dist/assets/vendor-xterm-DBb3RXlu.js +0 -66
  155. package/client/dist/assets/vendor-xterm-DrlLKa8f.css +0 -1
  156. package/client/dist/llms.txt +0 -40
  157. package/client/dist/robots.txt +0 -11
  158. package/client/dist/sitemap.xml +0 -45
package/server/cli.js CHANGED
@@ -6,9 +6,10 @@
6
6
  * Visual AI coding interface with Upfyn-Canvas for AI coding assistants
7
7
  *
8
8
  * Commands:
9
- * (no args) - Start the server (default)
9
+ * (no args) - Launch Claude Code with Upfyn branding (default)
10
10
  * start - Start the server
11
11
  * connect - Connect to hosted server (relay bridge)
12
+ * config - View/set configuration (API key, server, etc.)
12
13
  * status - Show configuration and data locations
13
14
  * help - Show help information
14
15
  * version - Show version information
@@ -19,6 +20,7 @@ import path from 'path';
19
20
  import os from 'os';
20
21
  import { fileURLToPath } from 'url';
21
22
  import { dirname } from 'path';
23
+ import { execSync, spawn } from 'child_process';
22
24
  import {
23
25
  c,
24
26
  showStyledHelp,
@@ -26,8 +28,12 @@ import {
26
28
  showServerBanner,
27
29
  showConnectStartup,
28
30
  showConnectionBanner,
31
+ showLaunchScreen,
32
+ showConfig,
29
33
  logRelayEvent,
30
34
  createSpinner,
35
+ playRocketAnimation,
36
+ clearScreen,
31
37
  } from './cli-ui.js';
32
38
 
33
39
  const __filename = fileURLToPath(import.meta.url);
@@ -37,6 +43,9 @@ const __dirname = dirname(__filename);
37
43
  const packageJsonPath = path.join(__dirname, '../package.json');
38
44
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
39
45
 
46
+ const CONFIG_DIR = path.join(os.homedir(), '.upfynai');
47
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
48
+
40
49
  // Load environment variables from .env file if it exists
41
50
  function loadEnvFile() {
42
51
  try {
@@ -56,6 +65,26 @@ function loadEnvFile() {
56
65
  }
57
66
  }
58
67
 
68
+ // Load saved config from ~/.upfynai/config.json
69
+ function loadConfig() {
70
+ try {
71
+ if (fs.existsSync(CONFIG_FILE)) {
72
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
73
+ }
74
+ } catch (e) { /* ignore */ }
75
+ return {};
76
+ }
77
+
78
+ // Save config to ~/.upfynai/config.json
79
+ function saveConfig(config) {
80
+ if (!fs.existsSync(CONFIG_DIR)) {
81
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
82
+ }
83
+ // Don't save internal keys
84
+ const { _path, ...rest } = config;
85
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(rest, null, 2));
86
+ }
87
+
59
88
  // Get the database path (same logic as db.js)
60
89
  function getDatabasePath() {
61
90
  loadEnvFile();
@@ -67,8 +96,29 @@ function getInstallDir() {
67
96
  return path.join(__dirname, '..');
68
97
  }
69
98
 
70
- // Show status command styled
99
+ // --- OS Detection + Claude Binary Discovery ---
100
+
101
+ function findClaudeBinary() {
102
+ const isWindows = process.platform === 'win32';
103
+ const candidates = isWindows
104
+ ? ['claude.exe', 'claude.cmd', 'claude']
105
+ : ['claude'];
106
+
107
+ for (const cmd of candidates) {
108
+ try {
109
+ const whichCmd = isWindows ? 'where' : 'which';
110
+ const result = execSync(`${whichCmd} ${cmd}`, { stdio: 'pipe', encoding: 'utf8' }).trim();
111
+ if (result) return cmd;
112
+ } catch {
113
+ // not found, try next
114
+ }
115
+ }
116
+ return null;
117
+ }
118
+
119
+ // --- Show status command ---
71
120
  function showStatus() {
121
+ const config = loadConfig();
72
122
  const installDir = getInstallDir();
73
123
  const dbPath = getDatabasePath();
74
124
  const dbExists = fs.existsSync(dbPath);
@@ -86,11 +136,12 @@ function showStatus() {
86
136
  dbSize,
87
137
  port: process.env.PORT || '3001',
88
138
  portDefault: !process.env.PORT,
89
- claudeCli: process.env.CLAUDE_CLI_PATH || null,
139
+ claudeCli: findClaudeBinary() || null,
140
+ apiKey: config.anthropicApiKey || null,
90
141
  });
91
142
  }
92
143
 
93
- // Show help — styled
144
+ // Show help
94
145
  function showHelp() {
95
146
  showStyledHelp(packageJson.version);
96
147
  }
@@ -114,18 +165,17 @@ function isNewerVersion(v1, v2) {
114
165
  // Check for updates
115
166
  async function checkForUpdates(silent = false) {
116
167
  try {
117
- const { execSync } = await import('child_process');
118
168
  const latestVersion = execSync('npm show upfynai-code version', { encoding: 'utf8' }).trim();
119
169
  const currentVersion = packageJson.version;
120
170
 
121
171
  if (isNewerVersion(latestVersion, currentVersion)) {
122
172
  if (!silent) {
123
- console.log(`\n ${c.yellow('')} New version available: ${c.bBright(latestVersion)} ${c.dim(`(current: ${currentVersion})`)}`);
173
+ console.log(`\n ${c.yellow('!')} New version available: ${c.bBright(latestVersion)} ${c.dim(`(current: ${currentVersion})`)}`);
124
174
  console.log(` Run ${c.bright('uc update')} to update\n`);
125
175
  }
126
176
  return { hasUpdate: true, latestVersion, currentVersion };
127
177
  } else if (!silent) {
128
- console.log(` ${c.green('')} You are on the latest version (${currentVersion})`);
178
+ console.log(` ${c.green('OK')} You are on the latest version (${currentVersion})`);
129
179
  }
130
180
  return { hasUpdate: false, latestVersion, currentVersion };
131
181
  } catch (e) {
@@ -139,7 +189,6 @@ async function checkForUpdates(silent = false) {
139
189
  // Update the package
140
190
  async function updatePackage() {
141
191
  try {
142
- const { execSync } = await import('child_process');
143
192
  const spinner = createSpinner('Checking for updates...');
144
193
  spinner.start();
145
194
 
@@ -148,20 +197,20 @@ async function updatePackage() {
148
197
  spinner.stop(`Already on the latest version (${currentVersion})`);
149
198
  return;
150
199
  }
151
- spinner.stop(`Update available: ${currentVersion} ${latestVersion}`);
200
+ spinner.stop(`Update available: ${currentVersion} -> ${latestVersion}`);
152
201
 
153
202
  const installSpinner = createSpinner(`Updating to v${latestVersion}...`);
154
203
  installSpinner.start();
155
204
  execSync('npm update -g upfynai-code', { stdio: 'pipe' });
156
205
  installSpinner.stop(`Updated to v${latestVersion}! Restart uc to use the new version.`);
157
206
  } catch (e) {
158
- console.log(` ${c.red('')} Update failed: ${e.message}`);
207
+ console.log(` ${c.red('FAIL')} Update failed: ${e.message}`);
159
208
  console.log(` ${c.dim('Try running manually:')} ${c.bright('npm update -g upfynai-code')}`);
160
209
  }
161
210
  }
162
211
 
163
212
  // Install slash commands to ~/.claude/commands/
164
- async function installCommands() {
213
+ async function installCommands(silent = false) {
165
214
  const commandsSource = path.join(__dirname, '..', 'commands');
166
215
  const commandsDest = path.join(os.homedir(), '.claude', 'commands');
167
216
 
@@ -170,8 +219,8 @@ async function installCommands() {
170
219
  }
171
220
 
172
221
  if (!fs.existsSync(commandsSource)) {
173
- console.log(` ${c.red('')} Commands directory not found`);
174
- process.exit(1);
222
+ if (!silent) console.log(` ${c.red('FAIL')} Commands directory not found`);
223
+ return 0;
175
224
  }
176
225
 
177
226
  const files = fs.readdirSync(commandsSource).filter(f => f.endsWith('.md'));
@@ -182,12 +231,17 @@ async function installCommands() {
182
231
  path.join(commandsSource, file),
183
232
  path.join(commandsDest, file)
184
233
  );
185
- console.log(` ${c.green('✓')} Installed ${c.violet('/' + file.replace('.md', ''))}`);
234
+ if (!silent) {
235
+ console.log(` ${c.green('OK')} Installed ${c.violet('/' + file.replace('.md', ''))}`);
236
+ }
186
237
  count++;
187
238
  }
188
239
 
189
- console.log(`\n ${c.bBright(`${count} slash commands installed!`)}`);
190
- console.log(` ${c.dim('Available in your AI CLI as /upfynai-*')}\n`);
240
+ if (!silent) {
241
+ console.log(`\n ${c.bBright(`${count} slash commands installed!`)}`);
242
+ console.log(` ${c.dim('Available in your AI CLI as /upfynai-*')}\n`);
243
+ }
244
+ return count;
191
245
  }
192
246
 
193
247
  // Remove slash commands from ~/.claude/commands/
@@ -204,12 +258,114 @@ async function uninstallCommands() {
204
258
 
205
259
  for (const file of files) {
206
260
  fs.unlinkSync(path.join(commandsDest, file));
207
- console.log(` ${c.green('')} Removed ${c.violet('/' + file.replace('.md', ''))}`);
261
+ console.log(` ${c.green('OK')} Removed ${c.violet('/' + file.replace('.md', ''))}`);
208
262
  }
209
263
 
210
264
  console.log(`\n ${c.bBright(`${files.length} slash commands removed.`)}\n`);
211
265
  }
212
266
 
267
+ // --- Config command ---
268
+ function handleConfig(options) {
269
+ const config = loadConfig();
270
+
271
+ if (options.apiKey) {
272
+ // Set API key
273
+ config.anthropicApiKey = options.apiKey;
274
+ saveConfig(config);
275
+ console.log(`\n ${c.green('OK')} ${c.white('Anthropic API key saved')}`);
276
+ console.log(` ${c.dim('Key:')} sk-ant-...${options.apiKey.slice(-4)}`);
277
+ console.log(` ${c.dim('Stored in:')} ${CONFIG_FILE}\n`);
278
+ return;
279
+ }
280
+
281
+ if (options.clearApiKey) {
282
+ delete config.anthropicApiKey;
283
+ saveConfig(config);
284
+ console.log(`\n ${c.green('OK')} ${c.white('Anthropic API key removed')}\n`);
285
+ return;
286
+ }
287
+
288
+ // Show current config
289
+ showConfig({ ...config, _path: CONFIG_FILE });
290
+ }
291
+
292
+ // --- Launch Interactive (default command) ---
293
+ async function launchInteractive() {
294
+ // 1. Play rocket animation
295
+ await playRocketAnimation();
296
+ clearScreen();
297
+
298
+ // 2. Ensure slash commands are installed (silent)
299
+ await installCommands(true);
300
+
301
+ // 3. Find Claude Code binary
302
+ const claudeBin = findClaudeBinary();
303
+
304
+ // 4. Load config for relay + API key
305
+ const config = loadConfig();
306
+
307
+ // 5. Show launch screen
308
+ showLaunchScreen(packageJson.version, claudeBin, {
309
+ relayStatus: config.relayKey && config.server
310
+ ? `Auto-connecting to ${config.server}`
311
+ : null,
312
+ apiKey: config.anthropicApiKey || null,
313
+ });
314
+
315
+ // 6. If Claude Code not found, fall back to server mode
316
+ if (!claudeBin) {
317
+ console.log(` ${c.dim('Falling back to server mode...')}\n`);
318
+ await startServer();
319
+ return;
320
+ }
321
+
322
+ // 7. Build environment for Claude Code
323
+ const childEnv = { ...process.env };
324
+ if (config.anthropicApiKey) {
325
+ childEnv.ANTHROPIC_API_KEY = config.anthropicApiKey;
326
+ }
327
+
328
+ // 8. Start background relay if config exists
329
+ if (config.relayKey && config.server) {
330
+ startBackgroundRelay(config);
331
+ }
332
+
333
+ // 9. Spawn Claude Code interactively
334
+ const child = spawn(claudeBin, [], {
335
+ stdio: 'inherit',
336
+ cwd: process.cwd(),
337
+ shell: true,
338
+ env: childEnv,
339
+ });
340
+
341
+ child.on('exit', (code) => {
342
+ process.exit(code || 0);
343
+ });
344
+
345
+ child.on('error', (err) => {
346
+ console.log(`\n ${c.red('FAIL')} Failed to launch Claude Code: ${err.message}`);
347
+ console.log(` ${c.dim('Make sure Claude Code is installed:')}`);
348
+ console.log(` ${c.bright('npm install -g @anthropic-ai/claude-code')}\n`);
349
+ process.exit(1);
350
+ });
351
+ }
352
+
353
+ // --- Background relay connection ---
354
+ function startBackgroundRelay(config) {
355
+ // Import and start relay in background (non-blocking)
356
+ import('./relay-client.js').then(({ connectToServerBackground }) => {
357
+ if (typeof connectToServerBackground === 'function') {
358
+ connectToServerBackground({
359
+ server: config.server,
360
+ key: config.relayKey,
361
+ silent: true,
362
+ });
363
+ }
364
+ }).catch(() => {
365
+ // Relay module not available or no background connect — that's ok
366
+ });
367
+ }
368
+
213
369
  // Start the server
214
370
  async function startServer() {
215
371
  // Check for updates silently on startup
@@ -225,7 +381,7 @@ async function startServer() {
225
381
 
226
382
  // Parse CLI arguments
227
383
  function parseArgs(args) {
228
- const parsed = { command: 'start', options: {} };
384
+ const parsed = { command: null, options: {} };
229
385
 
230
386
  for (let i = 0; i < args.length; i++) {
231
387
  const arg = args[i];
@@ -246,15 +402,26 @@ function parseArgs(args) {
246
402
  parsed.options.key = args[++i];
247
403
  } else if (arg.startsWith('--key=')) {
248
404
  parsed.options.key = arg.split('=')[1];
405
+ } else if (arg === '--api-key') {
406
+ parsed.options.apiKey = args[++i];
407
+ } else if (arg.startsWith('--api-key=')) {
408
+ parsed.options.apiKey = arg.split('=')[1];
409
+ } else if (arg === '--clear-api-key') {
410
+ parsed.options.clearApiKey = true;
249
411
  } else if (arg === '--help' || arg === '-h') {
250
412
  parsed.command = 'help';
251
413
  } else if (arg === '--version' || arg === '-v') {
252
414
  parsed.command = 'version';
253
- } else if (!arg.startsWith('-')) {
415
+ } else if (!arg.startsWith('-') && !parsed.command) {
254
416
  parsed.command = arg;
255
417
  }
256
418
  }
257
419
 
420
+ // Default command: launch interactive
421
+ if (!parsed.command) {
422
+ parsed.command = 'launch';
423
+ }
424
+
258
425
  return parsed;
259
426
  }
260
427
 
@@ -272,6 +439,9 @@ async function main() {
272
439
  }
273
440
 
274
441
  switch (command) {
442
+ case 'launch':
443
+ await launchInteractive();
444
+ break;
275
445
  case 'start':
276
446
  await startServer();
277
447
  break;
@@ -292,6 +462,9 @@ async function main() {
292
462
  case 'update':
293
463
  await updatePackage();
294
464
  break;
465
+ case 'config':
466
+ handleConfig(options);
467
+ break;
295
468
  case 'install-commands':
296
469
  await installCommands();
297
470
  break;
@@ -307,7 +480,7 @@ async function main() {
307
480
  break;
308
481
  }
309
482
  default:
310
- console.error(`\n ${c.red('')} Unknown command: ${command}`);
483
+ console.error(`\n ${c.red('FAIL')} Unknown command: ${command}`);
311
484
  console.log(` Run ${c.bright('"uc help"')} for usage information.\n`);
312
485
  process.exit(1);
313
486
  }
@@ -315,6 +488,6 @@ async function main() {
315
488
 
316
489
  // Run the CLI
317
490
  main().catch(error => {
318
- console.error(`\n ${c.red('')} Error: ${error.message}`);
491
+ console.error(`\n ${c.red('FAIL')} Error: ${error.message}`);
319
492
  process.exit(1);
320
493
  });