upfynai-code 2.8.0 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/scripts/postinstall.js +9 -0
- package/src/animation.js +228 -0
- package/src/connect.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "upfynai-code",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.1",
|
|
4
4
|
"description": "Unified AI coding interface — access AI chat, terminal, file explorer, git, and visual canvas from any browser. Connect your local machine and code from anywhere.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
19
|
"start": "node bin/cli.js",
|
|
20
|
+
"postinstall": "node scripts/postinstall.js",
|
|
20
21
|
"prepublishOnly": "node scripts/prepublish.js"
|
|
21
22
|
},
|
|
22
23
|
"keywords": [
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { playInstallAnimation } from '../src/animation.js';
|
|
3
|
+
|
|
4
|
+
try {
|
|
5
|
+
await playInstallAnimation();
|
|
6
|
+
} catch {
|
|
7
|
+
// Silently fail — animation is cosmetic, don't break installs
|
|
8
|
+
console.log('\n ✓ upfynai-code installed. Run `uc --help` to get started.\n');
|
|
9
|
+
}
|
package/src/animation.js
ADDED
|
@@ -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/connect.js
CHANGED
|
@@ -9,6 +9,7 @@ import { readConfig, writeConfig, displayUrl } from './config.js';
|
|
|
9
9
|
import { getToken, validateToken } from './auth.js';
|
|
10
10
|
import { getPersistentShell } from './persistent-shell.js';
|
|
11
11
|
import { needsPermission, requestPermission, handlePermissionResponse } from './permissions.js';
|
|
12
|
+
import { playConnectAnimation } from './animation.js';
|
|
12
13
|
|
|
13
14
|
// Resolve agents: dist/agents/ (npm package) or ../../shared/agents/ (monorepo)
|
|
14
15
|
const __connectDir = dirname(fileURLToPath(import.meta.url));
|
|
@@ -220,6 +221,9 @@ export async function connect(options = {}) {
|
|
|
220
221
|
|
|
221
222
|
const wsUrl = serverUrl.replace(/^http/, 'ws') + '/relay?token=' + encodeURIComponent(relayKey);
|
|
222
223
|
|
|
224
|
+
// Play spaceship launch animation
|
|
225
|
+
try { await playConnectAnimation(); } catch { /* cosmetic — don't block connect */ }
|
|
226
|
+
|
|
223
227
|
console.log(chalk.bold('\n Upfyn-Code Relay Client\n'));
|
|
224
228
|
console.log(` Server: ${chalk.cyan(displayUrl(serverUrl))}`);
|
|
225
229
|
console.log(` Machine: ${chalk.dim(os.hostname())}`);
|