fluxy-bot 0.3.27 → 0.4.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/bin/cli.js +148 -13
- package/package.json +2 -3
- package/scripts/install +69 -35
- package/scripts/install.ps1 +121 -40
- package/scripts/install.sh +69 -35
- package/scripts/postinstall.js +21 -9
package/bin/cli.js
CHANGED
|
@@ -30,15 +30,32 @@ const c = {
|
|
|
30
30
|
yellow: '\x1b[33m',
|
|
31
31
|
red: '\x1b[31m',
|
|
32
32
|
white: '\x1b[97m',
|
|
33
|
+
blue: '\x1b[38;2;50;165;247m',
|
|
34
|
+
pink: '\x1b[38;2;219;54;163m',
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
36
38
|
const BAR_WIDTH = 30;
|
|
37
39
|
|
|
40
|
+
function gradientChar(i, total) {
|
|
41
|
+
const t = total > 1 ? i / (total - 1) : 0;
|
|
42
|
+
const r = Math.round(50 + t * (219 - 50));
|
|
43
|
+
const g = Math.round(165 + t * (54 - 165));
|
|
44
|
+
const b = Math.round(247 + t * (163 - 247));
|
|
45
|
+
return `\x1b[38;2;${r};${g};${b}m`;
|
|
46
|
+
}
|
|
47
|
+
|
|
38
48
|
function progressBar(ratio, width = BAR_WIDTH) {
|
|
39
49
|
const filled = Math.round(ratio * width);
|
|
40
50
|
const empty = width - filled;
|
|
41
|
-
|
|
51
|
+
let bar = '';
|
|
52
|
+
for (let i = 0; i < filled; i++) bar += `${gradientChar(i, width)}█`;
|
|
53
|
+
bar += `${c.dim}${'░'.repeat(empty)}${c.reset}`;
|
|
54
|
+
return bar;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function link(url) {
|
|
58
|
+
return `\x1b]8;;${url}\x07${url}\x1b]8;;\x07`;
|
|
42
59
|
}
|
|
43
60
|
|
|
44
61
|
class Stepper {
|
|
@@ -70,9 +87,9 @@ class Stepper {
|
|
|
70
87
|
|
|
71
88
|
for (let i = 0; i < this.steps.length; i++) {
|
|
72
89
|
if (i < this.current) {
|
|
73
|
-
console.log(` ${c.
|
|
90
|
+
console.log(` ${c.blue}✔${c.reset} ${this.steps[i]}`);
|
|
74
91
|
} else if (i === this.current) {
|
|
75
|
-
console.log(` ${c.
|
|
92
|
+
console.log(` ${c.pink}${SPINNER[this.frame]}${c.reset} ${this.steps[i]}${c.dim}...${c.reset}`);
|
|
76
93
|
} else {
|
|
77
94
|
console.log(` ${c.dim}○ ${this.steps[i]}${c.reset}`);
|
|
78
95
|
}
|
|
@@ -92,18 +109,19 @@ class Stepper {
|
|
|
92
109
|
|
|
93
110
|
process.stdout.write(`\x1b[${this.steps.length + 2}A`);
|
|
94
111
|
for (const step of this.steps) {
|
|
95
|
-
console.log(` ${c.
|
|
112
|
+
console.log(` ${c.blue}✔${c.reset} ${step}`);
|
|
96
113
|
}
|
|
97
|
-
console.log(`\n ${progressBar(1)} ${c.
|
|
114
|
+
console.log(`\n ${progressBar(1)} ${c.pink}Done${c.reset}`);
|
|
98
115
|
}
|
|
99
116
|
}
|
|
100
117
|
|
|
101
118
|
function banner() {
|
|
102
119
|
console.log(`
|
|
103
|
-
${c.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
${c.
|
|
120
|
+
${c.blue}${c.bold} ___ __ ${c.reset}
|
|
121
|
+
${c.blue}${c.bold} / _/ / / __ __ __ __ __ ${c.reset}
|
|
122
|
+
${c.pink}${c.bold} / _/ / / / / / / \\ \\/ / / / ${c.reset}
|
|
123
|
+
${c.pink}${c.bold} /_/ /_/ \\_,_/ /_/\\_\\ /_/ ${c.reset}
|
|
124
|
+
${c.dim}v${pkg.version} · Self-hosted AI bot${c.reset}`);
|
|
107
125
|
}
|
|
108
126
|
|
|
109
127
|
function finalMessage(tunnelUrl, relayUrl) {
|
|
@@ -112,13 +130,14 @@ function finalMessage(tunnelUrl, relayUrl) {
|
|
|
112
130
|
|
|
113
131
|
${c.bold}${c.white}Open your dashboard to finish setup:${c.reset}
|
|
114
132
|
|
|
115
|
-
${c.
|
|
133
|
+
${c.blue}${c.bold}${link(tunnelUrl)}${c.reset}
|
|
134
|
+
${c.dim}(cmd+click or ctrl+click to open)${c.reset}`);
|
|
116
135
|
|
|
117
136
|
if (relayUrl) {
|
|
118
137
|
console.log(`
|
|
119
138
|
${c.bold}${c.white}Your permanent URL:${c.reset}
|
|
120
139
|
|
|
121
|
-
${c.
|
|
140
|
+
${c.pink}${c.bold}${link(relayUrl)}${c.reset}`);
|
|
122
141
|
}
|
|
123
142
|
|
|
124
143
|
console.log(`
|
|
@@ -385,10 +404,10 @@ async function status() {
|
|
|
385
404
|
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
|
|
386
405
|
const res = await fetch(`http://localhost:${config.port}/api/health`);
|
|
387
406
|
const data = await res.json();
|
|
388
|
-
console.log(`\n ${c.
|
|
407
|
+
console.log(`\n ${c.blue}●${c.reset} Bot is running`);
|
|
389
408
|
console.log(` ${c.dim}Uptime: ${data.uptime}s${c.reset}`);
|
|
390
409
|
if (config.relay?.url) {
|
|
391
|
-
console.log(` ${c.dim}URL: ${config.relay.url}${c.reset}`);
|
|
410
|
+
console.log(` ${c.dim}URL: ${c.reset}${c.pink}${link(config.relay.url)}${c.reset}`);
|
|
392
411
|
}
|
|
393
412
|
console.log(` ${c.dim}Config: ${CONFIG_PATH}${c.reset}\n`);
|
|
394
413
|
} catch {
|
|
@@ -396,12 +415,128 @@ async function status() {
|
|
|
396
415
|
}
|
|
397
416
|
}
|
|
398
417
|
|
|
418
|
+
async function update() {
|
|
419
|
+
banner();
|
|
420
|
+
|
|
421
|
+
const currentVersion = pkg.version;
|
|
422
|
+
console.log(`\n ${c.dim}Current version: v${currentVersion}${c.reset}`);
|
|
423
|
+
console.log(` ${c.blue}⠋${c.reset} Checking for updates...\n`);
|
|
424
|
+
|
|
425
|
+
// Fetch latest package info from npm registry
|
|
426
|
+
let latest;
|
|
427
|
+
try {
|
|
428
|
+
const res = await fetch('https://registry.npmjs.org/fluxy-bot/latest');
|
|
429
|
+
if (!res.ok) throw new Error();
|
|
430
|
+
latest = await res.json();
|
|
431
|
+
} catch {
|
|
432
|
+
console.log(` ${c.red}✗${c.reset} Failed to check for updates\n`);
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
if (currentVersion === latest.version) {
|
|
437
|
+
console.log(` ${c.blue}✔${c.reset} Already up to date (v${currentVersion})\n`);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
console.log(` ${c.dim}v${currentVersion} → v${latest.version}${c.reset}\n`);
|
|
442
|
+
|
|
443
|
+
const steps = [
|
|
444
|
+
'Downloading update',
|
|
445
|
+
'Updating files',
|
|
446
|
+
'Installing dependencies',
|
|
447
|
+
'Building interface',
|
|
448
|
+
];
|
|
449
|
+
|
|
450
|
+
const stepper = new Stepper(steps);
|
|
451
|
+
stepper.start();
|
|
452
|
+
|
|
453
|
+
// Download tarball
|
|
454
|
+
const tarballUrl = latest.dist.tarball;
|
|
455
|
+
const tmpDir = path.join(os.tmpdir(), `fluxy-update-${Date.now()}`);
|
|
456
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
457
|
+
const tarball = path.join(tmpDir, 'fluxy.tgz');
|
|
458
|
+
|
|
459
|
+
try {
|
|
460
|
+
const res = await fetch(tarballUrl);
|
|
461
|
+
if (!res.ok) throw new Error();
|
|
462
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
463
|
+
fs.writeFileSync(tarball, buf);
|
|
464
|
+
execSync(`tar xzf "${tarball}" -C "${tmpDir}"`, { stdio: 'ignore' });
|
|
465
|
+
} catch {
|
|
466
|
+
stepper.finish();
|
|
467
|
+
console.log(`\n ${c.red}✗${c.reset} Download failed\n`);
|
|
468
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
469
|
+
process.exit(1);
|
|
470
|
+
}
|
|
471
|
+
stepper.advance();
|
|
472
|
+
|
|
473
|
+
const extracted = path.join(tmpDir, 'package');
|
|
474
|
+
|
|
475
|
+
// Update code directories (preserve workspace/ user data)
|
|
476
|
+
for (const dir of ['bin', 'supervisor', 'worker', 'shared', 'scripts']) {
|
|
477
|
+
const src = path.join(extracted, dir);
|
|
478
|
+
if (fs.existsSync(src)) {
|
|
479
|
+
fs.cpSync(src, path.join(DATA_DIR, dir), { recursive: true, force: true });
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Copy workspace template only if it doesn't exist yet
|
|
484
|
+
if (!fs.existsSync(path.join(DATA_DIR, 'workspace'))) {
|
|
485
|
+
const wsSrc = path.join(extracted, 'workspace');
|
|
486
|
+
if (fs.existsSync(wsSrc)) {
|
|
487
|
+
fs.cpSync(wsSrc, path.join(DATA_DIR, 'workspace'), { recursive: true });
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Update code files (never touches config.json, memory.db, etc.)
|
|
492
|
+
for (const file of ['package.json', 'vite.config.ts', 'vite.fluxy.config.ts', 'tsconfig.json', 'postcss.config.js', 'components.json']) {
|
|
493
|
+
const src = path.join(extracted, file);
|
|
494
|
+
if (fs.existsSync(src)) {
|
|
495
|
+
fs.copyFileSync(src, path.join(DATA_DIR, file));
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// Update pre-built UI from tarball
|
|
500
|
+
const distSrc = path.join(extracted, 'dist-fluxy');
|
|
501
|
+
const distDst = path.join(DATA_DIR, 'dist-fluxy');
|
|
502
|
+
if (fs.existsSync(distSrc)) {
|
|
503
|
+
if (fs.existsSync(distDst)) fs.rmSync(distDst, { recursive: true });
|
|
504
|
+
fs.cpSync(distSrc, distDst, { recursive: true });
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
stepper.advance();
|
|
508
|
+
|
|
509
|
+
// Install dependencies
|
|
510
|
+
try {
|
|
511
|
+
execSync('npm install --omit=dev', { cwd: DATA_DIR, stdio: 'ignore' });
|
|
512
|
+
} catch {}
|
|
513
|
+
stepper.advance();
|
|
514
|
+
|
|
515
|
+
// Rebuild UI if not in tarball
|
|
516
|
+
if (!fs.existsSync(path.join(distDst, 'onboard.html'))) {
|
|
517
|
+
try {
|
|
518
|
+
if (fs.existsSync(distDst)) fs.rmSync(distDst, { recursive: true });
|
|
519
|
+
execSync('npm run build:fluxy', { cwd: DATA_DIR, stdio: 'ignore' });
|
|
520
|
+
} catch {}
|
|
521
|
+
}
|
|
522
|
+
stepper.advance();
|
|
523
|
+
|
|
524
|
+
// Clean up
|
|
525
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
526
|
+
|
|
527
|
+
stepper.finish();
|
|
528
|
+
|
|
529
|
+
console.log(`\n ${c.blue}${c.bold}✔ Updated to v${latest.version}${c.reset}\n`);
|
|
530
|
+
console.log(` ${c.dim}Run ${c.reset}${c.pink}fluxy start${c.reset}${c.dim} to launch.${c.reset}\n`);
|
|
531
|
+
}
|
|
532
|
+
|
|
399
533
|
// ── Route ──
|
|
400
534
|
|
|
401
535
|
switch (command) {
|
|
402
536
|
case 'init': init(); break;
|
|
403
537
|
case 'start': start(); break;
|
|
404
538
|
case 'status': status(); break;
|
|
539
|
+
case 'update': update(); break;
|
|
405
540
|
default:
|
|
406
541
|
fs.existsSync(CONFIG_PATH) ? start() : init();
|
|
407
542
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fluxy-bot",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Self-hosted AI
|
|
3
|
+
"version": "0.4.1",
|
|
4
|
+
"description": "Self-hosted, self-evolving AI agent with its own dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
@@ -20,7 +20,6 @@
|
|
|
20
20
|
"tsconfig.json",
|
|
21
21
|
"postcss.config.js",
|
|
22
22
|
"components.json",
|
|
23
|
-
"install.sh",
|
|
24
23
|
"install.ps1"
|
|
25
24
|
],
|
|
26
25
|
"keywords": [
|
package/scripts/install
CHANGED
|
@@ -15,18 +15,23 @@ NODE_DIR="$TOOLS_DIR/node"
|
|
|
15
15
|
BIN_DIR="$FLUXY_HOME/bin"
|
|
16
16
|
USE_SYSTEM_NODE=false
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# Brand colors: #32A5F7 (blue) and #DB36A3 (pink) via 256-color approximation
|
|
19
|
+
BLUE='\033[38;2;50;165;247m'
|
|
20
|
+
PINK='\033[38;2;219;54;163m'
|
|
20
21
|
YELLOW='\033[33m'
|
|
21
22
|
RED='\033[31m'
|
|
22
23
|
DIM='\033[2m'
|
|
23
24
|
BOLD='\033[1m'
|
|
24
25
|
RESET='\033[0m'
|
|
25
26
|
|
|
26
|
-
printf "\n
|
|
27
|
-
printf "${
|
|
28
|
-
printf "${
|
|
29
|
-
printf "${
|
|
27
|
+
printf "\n"
|
|
28
|
+
printf "${BLUE}${BOLD} ___ __ ${RESET}\n"
|
|
29
|
+
printf "${BLUE}${BOLD} / _/ / / __ __ __ __ __ ${RESET}\n"
|
|
30
|
+
printf "${PINK}${BOLD} / _/ / / / / / / \\ \\/ / / / ${RESET}\n"
|
|
31
|
+
printf "${PINK}${BOLD} /_/ /_/ \\_,_/ /_/\\_\\ /_/ ${RESET}\n"
|
|
32
|
+
printf "\n"
|
|
33
|
+
printf "${DIM} Self-hosted, self-evolving AI agent with its own dashboard.${RESET}\n"
|
|
34
|
+
printf "${DIM} ─────────────────────────────${RESET}\n\n"
|
|
30
35
|
|
|
31
36
|
# ─── Detect platform ────────────────────────────────────────────────────────
|
|
32
37
|
|
|
@@ -65,7 +70,7 @@ check_system_node() {
|
|
|
65
70
|
MAJOR=$(echo "$SYS_NODE_VERSION" | sed 's/^v//' | cut -d. -f1)
|
|
66
71
|
if [ "$MAJOR" -ge "$MIN_NODE_MAJOR" ] 2>/dev/null; then
|
|
67
72
|
USE_SYSTEM_NODE=true
|
|
68
|
-
printf " ${
|
|
73
|
+
printf " ${BLUE}✔${RESET} Node.js ${SYS_NODE_VERSION} (system)\n"
|
|
69
74
|
return 0
|
|
70
75
|
fi
|
|
71
76
|
fi
|
|
@@ -80,12 +85,12 @@ install_node() {
|
|
|
80
85
|
if [ -x "$NODE_DIR/bin/node" ]; then
|
|
81
86
|
EXISTING=$("$NODE_DIR/bin/node" -v 2>/dev/null || echo "")
|
|
82
87
|
if [ -n "$EXISTING" ]; then
|
|
83
|
-
printf " ${
|
|
88
|
+
printf " ${BLUE}✔${RESET} Node.js ${EXISTING} (bundled)\n"
|
|
84
89
|
return 0
|
|
85
90
|
fi
|
|
86
91
|
fi
|
|
87
92
|
|
|
88
|
-
printf " ${
|
|
93
|
+
printf " ${BLUE}↓${RESET} Downloading Node.js v${NODE_VERSION}...\n"
|
|
89
94
|
|
|
90
95
|
NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-${PLATFORM}-${NODEARCH}.tar.xz"
|
|
91
96
|
TMPFILE=$(mktemp /tmp/node-XXXXXX.tar.xz)
|
|
@@ -114,7 +119,7 @@ install_node() {
|
|
|
114
119
|
exit 1
|
|
115
120
|
fi
|
|
116
121
|
|
|
117
|
-
printf " ${
|
|
122
|
+
printf " ${BLUE}✔${RESET} Node.js v${NODE_VERSION} installed\n"
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
# ─── Install Fluxy ────────────────────────────────────────────────────────
|
|
@@ -128,9 +133,14 @@ install_fluxy() {
|
|
|
128
133
|
NODE="$NODE_DIR/bin/node"
|
|
129
134
|
fi
|
|
130
135
|
|
|
131
|
-
|
|
136
|
+
# Fetch version + tarball URL from npm registry
|
|
137
|
+
NPM_VERSION=$("$NPM" view fluxy-bot version 2>/dev/null || echo "")
|
|
138
|
+
if [ -n "$NPM_VERSION" ]; then
|
|
139
|
+
printf " ${DIM}Latest npm version: fluxy-bot@${NPM_VERSION}${RESET}\n"
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
printf " ${BLUE}↓${RESET} Installing fluxy...\n"
|
|
132
143
|
|
|
133
|
-
# Get tarball URL from npm registry
|
|
134
144
|
TARBALL_URL=$("$NPM" view fluxy-bot dist.tarball 2>/dev/null)
|
|
135
145
|
if [ -z "$TARBALL_URL" ]; then
|
|
136
146
|
printf " ${RED}✗${RESET} Failed to fetch package info from npm\n"
|
|
@@ -154,26 +164,42 @@ install_fluxy() {
|
|
|
154
164
|
exit 1
|
|
155
165
|
fi
|
|
156
166
|
|
|
157
|
-
# Copy
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
167
|
+
# Copy code directories (always safe to overwrite)
|
|
168
|
+
for dir in bin supervisor worker shared scripts; do
|
|
169
|
+
[ -d "$EXTRACTED/$dir" ] && cp -r "$EXTRACTED/$dir" "$FLUXY_HOME/"
|
|
170
|
+
done
|
|
161
171
|
|
|
162
|
-
#
|
|
163
|
-
|
|
172
|
+
# Copy workspace template only on first install (preserves user files)
|
|
173
|
+
if [ ! -d "$FLUXY_HOME/workspace" ]; then
|
|
174
|
+
[ -d "$EXTRACTED/workspace" ] && cp -r "$EXTRACTED/workspace" "$FLUXY_HOME/"
|
|
175
|
+
fi
|
|
164
176
|
|
|
165
|
-
#
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
177
|
+
# Copy code files (never touches config.json, memory.db, etc.)
|
|
178
|
+
for f in package.json vite.config.ts vite.fluxy.config.ts tsconfig.json postcss.config.js components.json; do
|
|
179
|
+
[ -f "$EXTRACTED/$f" ] && cp "$EXTRACTED/$f" "$FLUXY_HOME/"
|
|
180
|
+
done
|
|
181
|
+
|
|
182
|
+
# Copy pre-built UI from tarball, or build from source
|
|
183
|
+
if [ -d "$EXTRACTED/dist-fluxy" ]; then
|
|
184
|
+
rm -rf "$FLUXY_HOME/dist-fluxy"
|
|
185
|
+
cp -r "$EXTRACTED/dist-fluxy" "$FLUXY_HOME/"
|
|
186
|
+
printf " ${BLUE}✔${RESET} Chat interface ready\n"
|
|
187
|
+
elif [ ! -f "$FLUXY_HOME/dist-fluxy/onboard.html" ]; then
|
|
188
|
+
printf " ${BLUE}↓${RESET} Building chat interface...\n"
|
|
170
189
|
if (cd "$FLUXY_HOME" && "$NPM" run build:fluxy 2>/dev/null); then
|
|
171
|
-
printf " ${
|
|
190
|
+
printf " ${BLUE}✔${RESET} Chat interface built\n"
|
|
172
191
|
else
|
|
173
192
|
printf " ${YELLOW}!${RESET} Chat build skipped — will build on first start\n"
|
|
174
193
|
fi
|
|
194
|
+
else
|
|
195
|
+
printf " ${BLUE}✔${RESET} Chat interface ready\n"
|
|
175
196
|
fi
|
|
176
197
|
|
|
198
|
+
rm -rf "$TMPDIR"
|
|
199
|
+
|
|
200
|
+
# Install dependencies inside ~/.fluxy/
|
|
201
|
+
(cd "$FLUXY_HOME" && "$NPM" install --omit=dev 2>/dev/null)
|
|
202
|
+
|
|
177
203
|
# Verify
|
|
178
204
|
if [ ! -f "$FLUXY_HOME/bin/cli.js" ]; then
|
|
179
205
|
printf " ${RED}✗${RESET} Installation failed\n"
|
|
@@ -182,7 +208,7 @@ install_fluxy() {
|
|
|
182
208
|
|
|
183
209
|
VERSION=$("$NODE" -e "const p=JSON.parse(require('fs').readFileSync('$FLUXY_HOME/package.json','utf8'));console.log(p.version)" 2>/dev/null || echo "unknown")
|
|
184
210
|
|
|
185
|
-
printf " ${
|
|
211
|
+
printf " ${BLUE}✔${RESET} Fluxy v${VERSION} installed\n"
|
|
186
212
|
}
|
|
187
213
|
|
|
188
214
|
# ─── Create wrapper script ──────────────────────────────────────────────────
|
|
@@ -210,7 +236,7 @@ WRAPPER
|
|
|
210
236
|
fi
|
|
211
237
|
|
|
212
238
|
chmod +x "$BIN_DIR/fluxy"
|
|
213
|
-
printf " ${
|
|
239
|
+
printf " ${BLUE}✔${RESET} Created ${DIM}~/.fluxy/bin/fluxy${RESET}\n"
|
|
214
240
|
}
|
|
215
241
|
|
|
216
242
|
# ─── Add to PATH ────────────────────────────────────────────────────────────
|
|
@@ -244,7 +270,7 @@ setup_path() {
|
|
|
244
270
|
if ! grep -q "fluxy/bin" "$HOME/.config/fish/config.fish" 2>/dev/null; then
|
|
245
271
|
echo 'set -gx PATH "$HOME/.fluxy/bin" $PATH' >> "$HOME/.config/fish/config.fish"
|
|
246
272
|
fi
|
|
247
|
-
printf " ${
|
|
273
|
+
printf " ${BLUE}✔${RESET} Added to PATH ${DIM}(~/.config/fish/config.fish)${RESET}\n"
|
|
248
274
|
return 0
|
|
249
275
|
;;
|
|
250
276
|
*) PROFILE="$HOME/.profile" ;;
|
|
@@ -254,7 +280,7 @@ setup_path() {
|
|
|
254
280
|
if ! grep -q "fluxy/bin" "$PROFILE" 2>/dev/null; then
|
|
255
281
|
printf "\n# Fluxy\n%s\n" "$EXPORT_LINE" >> "$PROFILE"
|
|
256
282
|
fi
|
|
257
|
-
printf " ${
|
|
283
|
+
printf " ${BLUE}✔${RESET} Added to PATH ${DIM}(${PROFILE})${RESET}\n"
|
|
258
284
|
fi
|
|
259
285
|
|
|
260
286
|
export PATH="$BIN_DIR:$PATH"
|
|
@@ -270,10 +296,18 @@ install_fluxy
|
|
|
270
296
|
create_wrapper
|
|
271
297
|
setup_path
|
|
272
298
|
|
|
273
|
-
printf "\n
|
|
274
|
-
printf "
|
|
275
|
-
printf "
|
|
276
|
-
printf "
|
|
277
|
-
printf "
|
|
278
|
-
printf "
|
|
279
|
-
printf "
|
|
299
|
+
printf "\n"
|
|
300
|
+
printf " ${PINK}${BOLD}✔ Fluxy is ready!${RESET}\n"
|
|
301
|
+
printf "\n"
|
|
302
|
+
printf " ${DIM}─────────────────────────────${RESET}\n"
|
|
303
|
+
printf " ${BOLD}Get started:${RESET}\n"
|
|
304
|
+
printf "\n"
|
|
305
|
+
printf " ${BLUE}fluxy init${RESET} Set up your bot\n"
|
|
306
|
+
printf " ${BLUE}fluxy start${RESET} Start your bot\n"
|
|
307
|
+
printf " ${BLUE}fluxy status${RESET} Check if it's running\n"
|
|
308
|
+
printf "\n"
|
|
309
|
+
printf " ${PINK}>${RESET} Run ${BLUE}fluxy init${RESET} to begin.\n"
|
|
310
|
+
printf " ${DIM}(Open a new terminal if 'fluxy' isn't found yet)${RESET}\n"
|
|
311
|
+
printf "\n"
|
|
312
|
+
printf " ${DIM}\033]8;;https://fluxy.bot\033\\https://fluxy.bot\033]8;;\033\\${RESET}\n"
|
|
313
|
+
printf "\n"
|
package/scripts/install.ps1
CHANGED
|
@@ -14,11 +14,43 @@ $NODE_DIR = Join-Path $TOOLS_DIR "node"
|
|
|
14
14
|
$BIN_DIR = Join-Path $FLUXY_HOME "bin"
|
|
15
15
|
$USE_SYSTEM_NODE = $false
|
|
16
16
|
|
|
17
|
+
# Ensure UTF-8 output for proper rendering
|
|
18
|
+
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
19
|
+
|
|
20
|
+
# Brand colors via ANSI escape sequences: #32A5F7 (blue) and #DB36A3 (pink)
|
|
21
|
+
$BLUE = "`e[38;2;50;165;247m"
|
|
22
|
+
$PINK = "`e[38;2;219;54;163m"
|
|
23
|
+
$BOLD = "`e[1m"
|
|
24
|
+
$RSET = "`e[0m"
|
|
25
|
+
|
|
26
|
+
# Use ANSI sequences for consistent rendering; fallback to plain if no VT support
|
|
27
|
+
$vtSupported = $null -ne $env:WT_SESSION -or $PSVersionTable.PSVersion.Major -ge 7 -or $host.UI.SupportsVirtualTerminal
|
|
28
|
+
|
|
29
|
+
function Write-Check($text) {
|
|
30
|
+
if ($vtSupported) { Write-Host " ${BLUE}✔${RSET} $text" }
|
|
31
|
+
else { Write-Host " ✔ $text" -ForegroundColor Cyan }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function Write-Down($text) {
|
|
35
|
+
if ($vtSupported) { Write-Host " ${PINK}↓${RSET} $text" }
|
|
36
|
+
else { Write-Host " ↓ $text" -ForegroundColor Cyan }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Write-Host ""
|
|
40
|
+
if ($vtSupported) {
|
|
41
|
+
Write-Host "${BLUE}${BOLD} ___ __ ${RSET}"
|
|
42
|
+
Write-Host "${BLUE}${BOLD} / _/ / / __ __ __ __ __ ${RSET}"
|
|
43
|
+
Write-Host "${PINK}${BOLD} / _/ / / / / / / \ \/ / / / ${RSET}"
|
|
44
|
+
Write-Host "${PINK}${BOLD} /_/ /_/ \_,_/ /_/\_\ /_/ ${RSET}"
|
|
45
|
+
} else {
|
|
46
|
+
Write-Host " ___ __ " -ForegroundColor Cyan
|
|
47
|
+
Write-Host " / _/ / / __ __ __ __ __ " -ForegroundColor Cyan
|
|
48
|
+
Write-Host " / _/ / / / / / / \ \/ / / / " -ForegroundColor Magenta
|
|
49
|
+
Write-Host " /_/ /_/ \_,_/ /_/\_\ /_/ " -ForegroundColor Magenta
|
|
50
|
+
}
|
|
17
51
|
Write-Host ""
|
|
18
|
-
Write-Host "
|
|
19
|
-
Write-Host "
|
|
20
|
-
Write-Host " ╚═══════════════════════════════╝" -ForegroundColor Cyan
|
|
21
|
-
Write-Host " Self-hosted AI bot" -ForegroundColor DarkGray
|
|
52
|
+
Write-Host " Self-hosted, self-evolving AI agent with its own dashboard." -ForegroundColor DarkGray
|
|
53
|
+
Write-Host " -----------------------------" -ForegroundColor DarkGray
|
|
22
54
|
Write-Host ""
|
|
23
55
|
|
|
24
56
|
# ─── Detect platform ────────────────────────────────────────────────────────
|
|
@@ -50,7 +82,7 @@ function Check-SystemNode {
|
|
|
50
82
|
$major = [int]$Matches[1]
|
|
51
83
|
if ($major -ge $MIN_NODE_MAJOR) {
|
|
52
84
|
$script:USE_SYSTEM_NODE = $true
|
|
53
|
-
Write-
|
|
85
|
+
Write-Check "Node.js $ver (system)"
|
|
54
86
|
return $true
|
|
55
87
|
}
|
|
56
88
|
}
|
|
@@ -69,13 +101,13 @@ function Install-Node {
|
|
|
69
101
|
try {
|
|
70
102
|
$existing = & $nodeBin -v 2>$null
|
|
71
103
|
if ($existing) {
|
|
72
|
-
Write-
|
|
104
|
+
Write-Check "Node.js $existing (bundled)"
|
|
73
105
|
return
|
|
74
106
|
}
|
|
75
107
|
} catch {}
|
|
76
108
|
}
|
|
77
109
|
|
|
78
|
-
Write-
|
|
110
|
+
Write-Down "Downloading Node.js v${NODE_VERSION}..."
|
|
79
111
|
|
|
80
112
|
$nodeUrl = "https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-win-${NODEARCH}.zip"
|
|
81
113
|
$tmpFile = Join-Path ([System.IO.Path]::GetTempPath()) "node-fluxy.zip"
|
|
@@ -103,7 +135,7 @@ function Install-Node {
|
|
|
103
135
|
exit 1
|
|
104
136
|
}
|
|
105
137
|
|
|
106
|
-
Write-
|
|
138
|
+
Write-Check "Node.js v${NODE_VERSION} installed"
|
|
107
139
|
}
|
|
108
140
|
|
|
109
141
|
# ─── Install Fluxy ────────────────────────────────────────────────────────
|
|
@@ -117,9 +149,15 @@ function Install-Fluxy {
|
|
|
117
149
|
$NODE_BIN = Join-Path $NODE_DIR "node.exe"
|
|
118
150
|
}
|
|
119
151
|
|
|
120
|
-
|
|
152
|
+
# Fetch version + tarball URL from npm registry
|
|
153
|
+
$npmVersion = ""
|
|
154
|
+
try { $npmVersion = (& $NPM view fluxy-bot version 2>$null).Trim() } catch {}
|
|
155
|
+
if ($npmVersion) {
|
|
156
|
+
Write-Host " Latest npm version: fluxy-bot@${npmVersion}" -ForegroundColor DarkGray
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
Write-Down "Installing fluxy..."
|
|
121
160
|
|
|
122
|
-
# Get tarball URL from npm registry
|
|
123
161
|
$tarballUrl = (& $NPM view fluxy-bot dist.tarball 2>$null).Trim()
|
|
124
162
|
if (-not $tarballUrl) {
|
|
125
163
|
Write-Host " ✗ Failed to fetch package info from npm" -ForegroundColor Red
|
|
@@ -142,10 +180,52 @@ function Install-Fluxy {
|
|
|
142
180
|
exit 1
|
|
143
181
|
}
|
|
144
182
|
|
|
145
|
-
# Copy source files to ~/.fluxy/ (preserves existing config.json, memory.db, etc.)
|
|
146
183
|
New-Item -ItemType Directory -Path $FLUXY_HOME -Force | Out-Null
|
|
147
|
-
|
|
148
|
-
|
|
184
|
+
|
|
185
|
+
# Copy code directories (always safe to overwrite)
|
|
186
|
+
foreach ($dir in @("bin", "supervisor", "worker", "shared", "scripts")) {
|
|
187
|
+
$src = Join-Path $extracted $dir
|
|
188
|
+
if (Test-Path $src) {
|
|
189
|
+
Copy-Item -Path $src -Destination $FLUXY_HOME -Recurse -Force
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# Copy workspace template only on first install (preserves user files)
|
|
194
|
+
$wsDst = Join-Path $FLUXY_HOME "workspace"
|
|
195
|
+
if (-not (Test-Path $wsDst)) {
|
|
196
|
+
$wsSrc = Join-Path $extracted "workspace"
|
|
197
|
+
if (Test-Path $wsSrc) {
|
|
198
|
+
Copy-Item -Path $wsSrc -Destination $FLUXY_HOME -Recurse
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
# Copy code files (never touches config.json, memory.db, etc.)
|
|
203
|
+
foreach ($file in @("package.json", "vite.config.ts", "vite.fluxy.config.ts", "tsconfig.json", "postcss.config.js", "components.json")) {
|
|
204
|
+
$src = Join-Path $extracted $file
|
|
205
|
+
if (Test-Path $src) {
|
|
206
|
+
Copy-Item -Path $src -Destination (Join-Path $FLUXY_HOME $file) -Force
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
# Copy pre-built UI from tarball, or build from source
|
|
211
|
+
$distSrc = Join-Path $extracted "dist-fluxy"
|
|
212
|
+
$distDst = Join-Path $FLUXY_HOME "dist-fluxy"
|
|
213
|
+
if (Test-Path $distSrc) {
|
|
214
|
+
if (Test-Path $distDst) { Remove-Item $distDst -Recurse -Force }
|
|
215
|
+
Copy-Item -Path $distSrc -Destination $distDst -Recurse
|
|
216
|
+
Write-Check "Chat interface ready"
|
|
217
|
+
} elseif (-not (Test-Path (Join-Path $distDst "onboard.html"))) {
|
|
218
|
+
Write-Down "Building chat interface..."
|
|
219
|
+
Push-Location $FLUXY_HOME
|
|
220
|
+
try {
|
|
221
|
+
& $NPM run build:fluxy 2>$null
|
|
222
|
+
Write-Check "Chat interface built"
|
|
223
|
+
} catch {
|
|
224
|
+
Write-Host " ! Chat build failed — will build on first start" -ForegroundColor Yellow
|
|
225
|
+
}
|
|
226
|
+
Pop-Location
|
|
227
|
+
} else {
|
|
228
|
+
Write-Check "Chat interface ready"
|
|
149
229
|
}
|
|
150
230
|
} finally {
|
|
151
231
|
Remove-Item $tmpDir -Recurse -Force -ErrorAction SilentlyContinue
|
|
@@ -156,21 +236,6 @@ function Install-Fluxy {
|
|
|
156
236
|
try {
|
|
157
237
|
& $NPM install --omit=dev 2>$null
|
|
158
238
|
} catch {}
|
|
159
|
-
|
|
160
|
-
# Build fluxy chat + onboard (served as static files)
|
|
161
|
-
$distFluxy = Join-Path $FLUXY_HOME "dist-fluxy"
|
|
162
|
-
$onboardHtml = Join-Path $distFluxy "onboard.html"
|
|
163
|
-
if ((Test-Path $distFluxy) -and (Test-Path $onboardHtml)) {
|
|
164
|
-
Write-Host " ✔ Chat interface (pre-built)" -ForegroundColor Green
|
|
165
|
-
} else {
|
|
166
|
-
Write-Host " ↓ Building chat interface..." -ForegroundColor Cyan
|
|
167
|
-
try {
|
|
168
|
-
& $NPM run build:fluxy 2>$null
|
|
169
|
-
Write-Host " ✔ Chat interface built" -ForegroundColor Green
|
|
170
|
-
} catch {
|
|
171
|
-
Write-Host " ! Chat interface build failed — it will be built on first start" -ForegroundColor Yellow
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
239
|
Pop-Location
|
|
175
240
|
|
|
176
241
|
# Verify
|
|
@@ -186,7 +251,7 @@ function Install-Fluxy {
|
|
|
186
251
|
$script:VERSION = $pkgJson.version
|
|
187
252
|
} catch {}
|
|
188
253
|
|
|
189
|
-
Write-
|
|
254
|
+
Write-Check "Fluxy v${VERSION} installed"
|
|
190
255
|
}
|
|
191
256
|
|
|
192
257
|
# ─── Create wrapper script ──────────────────────────────────────────────────
|
|
@@ -211,7 +276,7 @@ node "%USERPROFILE%\.fluxy\bin\cli.js" %*
|
|
|
211
276
|
}
|
|
212
277
|
|
|
213
278
|
Set-Content -Path $wrapperPath -Value $wrapper -Encoding ASCII
|
|
214
|
-
Write-
|
|
279
|
+
Write-Check "Created ~/.fluxy/bin/fluxy.cmd"
|
|
215
280
|
}
|
|
216
281
|
|
|
217
282
|
# ─── Add to PATH ────────────────────────────────────────────────────────────
|
|
@@ -221,9 +286,9 @@ function Setup-Path {
|
|
|
221
286
|
if ($userPath -notlike "*$BIN_DIR*") {
|
|
222
287
|
[Environment]::SetEnvironmentVariable("Path", "$BIN_DIR;$userPath", "User")
|
|
223
288
|
$env:Path = "$BIN_DIR;$env:Path"
|
|
224
|
-
Write-
|
|
289
|
+
Write-Check "Added to PATH"
|
|
225
290
|
} else {
|
|
226
|
-
Write-
|
|
291
|
+
Write-Check "PATH already configured"
|
|
227
292
|
}
|
|
228
293
|
}
|
|
229
294
|
|
|
@@ -238,16 +303,32 @@ Create-Wrapper
|
|
|
238
303
|
Setup-Path
|
|
239
304
|
|
|
240
305
|
Write-Host ""
|
|
241
|
-
|
|
306
|
+
if ($vtSupported) {
|
|
307
|
+
Write-Host " ${PINK}${BOLD}✔ Fluxy is ready!${RSET}"
|
|
308
|
+
} else {
|
|
309
|
+
Write-Host " ✔ Fluxy is ready!" -ForegroundColor Magenta
|
|
310
|
+
}
|
|
242
311
|
Write-Host ""
|
|
312
|
+
Write-Host " -----------------------------" -ForegroundColor DarkGray
|
|
243
313
|
Write-Host " Get started:"
|
|
244
314
|
Write-Host ""
|
|
245
|
-
|
|
246
|
-
Write-Host " fluxy
|
|
247
|
-
Write-Host " fluxy
|
|
248
|
-
Write-Host ""
|
|
249
|
-
Write-Host "
|
|
250
|
-
Write-Host "fluxy init
|
|
251
|
-
|
|
315
|
+
if ($vtSupported) {
|
|
316
|
+
Write-Host " ${BLUE}fluxy init${RSET} Set up your bot"
|
|
317
|
+
Write-Host " ${BLUE}fluxy start${RSET} Start your bot"
|
|
318
|
+
Write-Host " ${BLUE}fluxy status${RSET} Check if it's running"
|
|
319
|
+
Write-Host ""
|
|
320
|
+
Write-Host " ${PINK}>${RSET} Run ${BLUE}fluxy init${RSET} to begin."
|
|
321
|
+
} else {
|
|
322
|
+
Write-Host " fluxy init " -ForegroundColor Cyan -NoNewline; Write-Host "Set up your bot"
|
|
323
|
+
Write-Host " fluxy start " -ForegroundColor Cyan -NoNewline; Write-Host "Start your bot"
|
|
324
|
+
Write-Host " fluxy status " -ForegroundColor Cyan -NoNewline; Write-Host "Check if it's running"
|
|
325
|
+
Write-Host ""
|
|
326
|
+
Write-Host " > " -ForegroundColor Magenta -NoNewline
|
|
327
|
+
Write-Host "Run " -NoNewline
|
|
328
|
+
Write-Host "fluxy init" -ForegroundColor Cyan -NoNewline
|
|
329
|
+
Write-Host " to begin."
|
|
330
|
+
}
|
|
252
331
|
Write-Host " (Open a new terminal if 'fluxy' isn't found yet)" -ForegroundColor DarkGray
|
|
253
332
|
Write-Host ""
|
|
333
|
+
Write-Host " https://fluxy.bot" -ForegroundColor DarkGray
|
|
334
|
+
Write-Host ""
|
package/scripts/install.sh
CHANGED
|
@@ -15,18 +15,23 @@ NODE_DIR="$TOOLS_DIR/node"
|
|
|
15
15
|
BIN_DIR="$FLUXY_HOME/bin"
|
|
16
16
|
USE_SYSTEM_NODE=false
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# Brand colors: #32A5F7 (blue) and #DB36A3 (pink) via 256-color approximation
|
|
19
|
+
BLUE='\033[38;2;50;165;247m'
|
|
20
|
+
PINK='\033[38;2;219;54;163m'
|
|
20
21
|
YELLOW='\033[33m'
|
|
21
22
|
RED='\033[31m'
|
|
22
23
|
DIM='\033[2m'
|
|
23
24
|
BOLD='\033[1m'
|
|
24
25
|
RESET='\033[0m'
|
|
25
26
|
|
|
26
|
-
printf "\n
|
|
27
|
-
printf "${
|
|
28
|
-
printf "${
|
|
29
|
-
printf "${
|
|
27
|
+
printf "\n"
|
|
28
|
+
printf "${BLUE}${BOLD} ___ __ ${RESET}\n"
|
|
29
|
+
printf "${BLUE}${BOLD} / _/ / / __ __ __ __ __ ${RESET}\n"
|
|
30
|
+
printf "${PINK}${BOLD} / _/ / / / / / / \\ \\/ / / / ${RESET}\n"
|
|
31
|
+
printf "${PINK}${BOLD} /_/ /_/ \\_,_/ /_/\\_\\ /_/ ${RESET}\n"
|
|
32
|
+
printf "\n"
|
|
33
|
+
printf "${DIM} Self-hosted, self-evolving AI agent with its own dashboard.${RESET}\n"
|
|
34
|
+
printf "${DIM} ─────────────────────────────${RESET}\n\n"
|
|
30
35
|
|
|
31
36
|
# ─── Detect platform ────────────────────────────────────────────────────────
|
|
32
37
|
|
|
@@ -65,7 +70,7 @@ check_system_node() {
|
|
|
65
70
|
MAJOR=$(echo "$SYS_NODE_VERSION" | sed 's/^v//' | cut -d. -f1)
|
|
66
71
|
if [ "$MAJOR" -ge "$MIN_NODE_MAJOR" ] 2>/dev/null; then
|
|
67
72
|
USE_SYSTEM_NODE=true
|
|
68
|
-
printf " ${
|
|
73
|
+
printf " ${BLUE}✔${RESET} Node.js ${SYS_NODE_VERSION} (system)\n"
|
|
69
74
|
return 0
|
|
70
75
|
fi
|
|
71
76
|
fi
|
|
@@ -80,12 +85,12 @@ install_node() {
|
|
|
80
85
|
if [ -x "$NODE_DIR/bin/node" ]; then
|
|
81
86
|
EXISTING=$("$NODE_DIR/bin/node" -v 2>/dev/null || echo "")
|
|
82
87
|
if [ -n "$EXISTING" ]; then
|
|
83
|
-
printf " ${
|
|
88
|
+
printf " ${BLUE}✔${RESET} Node.js ${EXISTING} (bundled)\n"
|
|
84
89
|
return 0
|
|
85
90
|
fi
|
|
86
91
|
fi
|
|
87
92
|
|
|
88
|
-
printf " ${
|
|
93
|
+
printf " ${BLUE}↓${RESET} Downloading Node.js v${NODE_VERSION}...\n"
|
|
89
94
|
|
|
90
95
|
NODE_URL="https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-${PLATFORM}-${NODEARCH}.tar.xz"
|
|
91
96
|
TMPFILE=$(mktemp /tmp/node-XXXXXX.tar.xz)
|
|
@@ -114,7 +119,7 @@ install_node() {
|
|
|
114
119
|
exit 1
|
|
115
120
|
fi
|
|
116
121
|
|
|
117
|
-
printf " ${
|
|
122
|
+
printf " ${BLUE}✔${RESET} Node.js v${NODE_VERSION} installed\n"
|
|
118
123
|
}
|
|
119
124
|
|
|
120
125
|
# ─── Install Fluxy ────────────────────────────────────────────────────────
|
|
@@ -128,9 +133,14 @@ install_fluxy() {
|
|
|
128
133
|
NODE="$NODE_DIR/bin/node"
|
|
129
134
|
fi
|
|
130
135
|
|
|
131
|
-
|
|
136
|
+
# Fetch version + tarball URL from npm registry
|
|
137
|
+
NPM_VERSION=$("$NPM" view fluxy-bot version 2>/dev/null || echo "")
|
|
138
|
+
if [ -n "$NPM_VERSION" ]; then
|
|
139
|
+
printf " ${DIM}Latest npm version: fluxy-bot@${NPM_VERSION}${RESET}\n"
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
printf " ${BLUE}↓${RESET} Installing fluxy...\n"
|
|
132
143
|
|
|
133
|
-
# Get tarball URL from npm registry
|
|
134
144
|
TARBALL_URL=$("$NPM" view fluxy-bot dist.tarball 2>/dev/null)
|
|
135
145
|
if [ -z "$TARBALL_URL" ]; then
|
|
136
146
|
printf " ${RED}✗${RESET} Failed to fetch package info from npm\n"
|
|
@@ -154,26 +164,42 @@ install_fluxy() {
|
|
|
154
164
|
exit 1
|
|
155
165
|
fi
|
|
156
166
|
|
|
157
|
-
# Copy
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
167
|
+
# Copy code directories (always safe to overwrite)
|
|
168
|
+
for dir in bin supervisor worker shared scripts; do
|
|
169
|
+
[ -d "$EXTRACTED/$dir" ] && cp -r "$EXTRACTED/$dir" "$FLUXY_HOME/"
|
|
170
|
+
done
|
|
161
171
|
|
|
162
|
-
#
|
|
163
|
-
|
|
172
|
+
# Copy workspace template only on first install (preserves user files)
|
|
173
|
+
if [ ! -d "$FLUXY_HOME/workspace" ]; then
|
|
174
|
+
[ -d "$EXTRACTED/workspace" ] && cp -r "$EXTRACTED/workspace" "$FLUXY_HOME/"
|
|
175
|
+
fi
|
|
164
176
|
|
|
165
|
-
#
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
177
|
+
# Copy code files (never touches config.json, memory.db, etc.)
|
|
178
|
+
for f in package.json vite.config.ts vite.fluxy.config.ts tsconfig.json postcss.config.js components.json; do
|
|
179
|
+
[ -f "$EXTRACTED/$f" ] && cp "$EXTRACTED/$f" "$FLUXY_HOME/"
|
|
180
|
+
done
|
|
181
|
+
|
|
182
|
+
# Copy pre-built UI from tarball, or build from source
|
|
183
|
+
if [ -d "$EXTRACTED/dist-fluxy" ]; then
|
|
184
|
+
rm -rf "$FLUXY_HOME/dist-fluxy"
|
|
185
|
+
cp -r "$EXTRACTED/dist-fluxy" "$FLUXY_HOME/"
|
|
186
|
+
printf " ${BLUE}✔${RESET} Chat interface ready\n"
|
|
187
|
+
elif [ ! -f "$FLUXY_HOME/dist-fluxy/onboard.html" ]; then
|
|
188
|
+
printf " ${BLUE}↓${RESET} Building chat interface...\n"
|
|
170
189
|
if (cd "$FLUXY_HOME" && "$NPM" run build:fluxy 2>/dev/null); then
|
|
171
|
-
printf " ${
|
|
190
|
+
printf " ${BLUE}✔${RESET} Chat interface built\n"
|
|
172
191
|
else
|
|
173
192
|
printf " ${YELLOW}!${RESET} Chat build skipped — will build on first start\n"
|
|
174
193
|
fi
|
|
194
|
+
else
|
|
195
|
+
printf " ${BLUE}✔${RESET} Chat interface ready\n"
|
|
175
196
|
fi
|
|
176
197
|
|
|
198
|
+
rm -rf "$TMPDIR"
|
|
199
|
+
|
|
200
|
+
# Install dependencies inside ~/.fluxy/
|
|
201
|
+
(cd "$FLUXY_HOME" && "$NPM" install --omit=dev 2>/dev/null)
|
|
202
|
+
|
|
177
203
|
# Verify
|
|
178
204
|
if [ ! -f "$FLUXY_HOME/bin/cli.js" ]; then
|
|
179
205
|
printf " ${RED}✗${RESET} Installation failed\n"
|
|
@@ -182,7 +208,7 @@ install_fluxy() {
|
|
|
182
208
|
|
|
183
209
|
VERSION=$("$NODE" -e "const p=JSON.parse(require('fs').readFileSync('$FLUXY_HOME/package.json','utf8'));console.log(p.version)" 2>/dev/null || echo "unknown")
|
|
184
210
|
|
|
185
|
-
printf " ${
|
|
211
|
+
printf " ${BLUE}✔${RESET} Fluxy v${VERSION} installed\n"
|
|
186
212
|
}
|
|
187
213
|
|
|
188
214
|
# ─── Create wrapper script ──────────────────────────────────────────────────
|
|
@@ -210,7 +236,7 @@ WRAPPER
|
|
|
210
236
|
fi
|
|
211
237
|
|
|
212
238
|
chmod +x "$BIN_DIR/fluxy"
|
|
213
|
-
printf " ${
|
|
239
|
+
printf " ${BLUE}✔${RESET} Created ${DIM}~/.fluxy/bin/fluxy${RESET}\n"
|
|
214
240
|
}
|
|
215
241
|
|
|
216
242
|
# ─── Add to PATH ────────────────────────────────────────────────────────────
|
|
@@ -244,7 +270,7 @@ setup_path() {
|
|
|
244
270
|
if ! grep -q "fluxy/bin" "$HOME/.config/fish/config.fish" 2>/dev/null; then
|
|
245
271
|
echo 'set -gx PATH "$HOME/.fluxy/bin" $PATH' >> "$HOME/.config/fish/config.fish"
|
|
246
272
|
fi
|
|
247
|
-
printf " ${
|
|
273
|
+
printf " ${BLUE}✔${RESET} Added to PATH ${DIM}(~/.config/fish/config.fish)${RESET}\n"
|
|
248
274
|
return 0
|
|
249
275
|
;;
|
|
250
276
|
*) PROFILE="$HOME/.profile" ;;
|
|
@@ -254,7 +280,7 @@ setup_path() {
|
|
|
254
280
|
if ! grep -q "fluxy/bin" "$PROFILE" 2>/dev/null; then
|
|
255
281
|
printf "\n# Fluxy\n%s\n" "$EXPORT_LINE" >> "$PROFILE"
|
|
256
282
|
fi
|
|
257
|
-
printf " ${
|
|
283
|
+
printf " ${BLUE}✔${RESET} Added to PATH ${DIM}(${PROFILE})${RESET}\n"
|
|
258
284
|
fi
|
|
259
285
|
|
|
260
286
|
export PATH="$BIN_DIR:$PATH"
|
|
@@ -270,10 +296,18 @@ install_fluxy
|
|
|
270
296
|
create_wrapper
|
|
271
297
|
setup_path
|
|
272
298
|
|
|
273
|
-
printf "\n
|
|
274
|
-
printf "
|
|
275
|
-
printf "
|
|
276
|
-
printf "
|
|
277
|
-
printf "
|
|
278
|
-
printf "
|
|
279
|
-
printf "
|
|
299
|
+
printf "\n"
|
|
300
|
+
printf " ${PINK}${BOLD}✔ Fluxy is ready!${RESET}\n"
|
|
301
|
+
printf "\n"
|
|
302
|
+
printf " ${DIM}─────────────────────────────${RESET}\n"
|
|
303
|
+
printf " ${BOLD}Get started:${RESET}\n"
|
|
304
|
+
printf "\n"
|
|
305
|
+
printf " ${BLUE}fluxy init${RESET} Set up your bot\n"
|
|
306
|
+
printf " ${BLUE}fluxy start${RESET} Start your bot\n"
|
|
307
|
+
printf " ${BLUE}fluxy status${RESET} Check if it's running\n"
|
|
308
|
+
printf "\n"
|
|
309
|
+
printf " ${PINK}>${RESET} Run ${BLUE}fluxy init${RESET} to begin.\n"
|
|
310
|
+
printf " ${DIM}(Open a new terminal if 'fluxy' isn't found yet)${RESET}\n"
|
|
311
|
+
printf "\n"
|
|
312
|
+
printf " ${DIM}\033]8;;https://fluxy.bot\033\\https://fluxy.bot\033]8;;\033\\${RESET}\n"
|
|
313
|
+
printf "\n"
|
package/scripts/postinstall.js
CHANGED
|
@@ -28,23 +28,30 @@ if (fs.existsSync(path.join(PKG_ROOT, '.git'))) {
|
|
|
28
28
|
|
|
29
29
|
fs.mkdirSync(FLUXY_HOME, { recursive: true });
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
];
|
|
31
|
+
// Code directories — always overwrite (these are application code)
|
|
32
|
+
const CODE_DIRS = ['bin', 'supervisor', 'worker', 'shared', 'scripts'];
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
// Code files — always overwrite
|
|
35
|
+
const CODE_FILES = [
|
|
36
36
|
'package.json', 'vite.config.ts', 'vite.fluxy.config.ts',
|
|
37
37
|
'tsconfig.json', 'postcss.config.js', 'components.json',
|
|
38
38
|
];
|
|
39
39
|
|
|
40
|
-
for (const dir of
|
|
40
|
+
for (const dir of CODE_DIRS) {
|
|
41
41
|
const src = path.join(PKG_ROOT, dir);
|
|
42
42
|
if (!fs.existsSync(src)) continue;
|
|
43
43
|
const dst = path.join(FLUXY_HOME, dir);
|
|
44
44
|
fs.cpSync(src, dst, { recursive: true, force: true });
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
// Workspace template — only on first install (preserves user files, uploads, etc.)
|
|
48
|
+
const wsSrc = path.join(PKG_ROOT, 'workspace');
|
|
49
|
+
const wsDst = path.join(FLUXY_HOME, 'workspace');
|
|
50
|
+
if (fs.existsSync(wsSrc) && !fs.existsSync(wsDst)) {
|
|
51
|
+
fs.cpSync(wsSrc, wsDst, { recursive: true });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
for (const file of CODE_FILES) {
|
|
48
55
|
const src = path.join(PKG_ROOT, file);
|
|
49
56
|
if (!fs.existsSync(src)) continue;
|
|
50
57
|
fs.copyFileSync(src, path.join(FLUXY_HOME, file));
|
|
@@ -61,10 +68,15 @@ try {
|
|
|
61
68
|
// Non-fatal: deps may already exist from a previous install
|
|
62
69
|
}
|
|
63
70
|
|
|
64
|
-
// ──
|
|
71
|
+
// ── Copy pre-built UI if available, otherwise build ──
|
|
65
72
|
|
|
66
|
-
const
|
|
67
|
-
|
|
73
|
+
const distSrc = path.join(PKG_ROOT, 'dist-fluxy');
|
|
74
|
+
const distDst = path.join(FLUXY_HOME, 'dist-fluxy');
|
|
75
|
+
if (fs.existsSync(distSrc)) {
|
|
76
|
+
// Always use the pre-built UI from the package (handles updates)
|
|
77
|
+
if (fs.existsSync(distDst)) fs.rmSync(distDst, { recursive: true });
|
|
78
|
+
fs.cpSync(distSrc, distDst, { recursive: true });
|
|
79
|
+
} else if (!fs.existsSync(path.join(distDst, 'onboard.html'))) {
|
|
68
80
|
try {
|
|
69
81
|
execSync('npm run build:fluxy', {
|
|
70
82
|
cwd: FLUXY_HOME,
|