fluxy-bot 0.5.44 → 0.5.46

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 CHANGED
@@ -242,6 +242,10 @@ function finalMessage(tunnelUrl, relayUrl) {
242
242
  }
243
243
  }
244
244
 
245
+ function writeVersionFile(version) {
246
+ try { fs.writeFileSync(path.join(DATA_DIR, 'VERSION'), version); } catch {}
247
+ }
248
+
245
249
  // ── Steps ──
246
250
 
247
251
  function createConfig() {
@@ -401,6 +405,7 @@ async function init() {
401
405
  banner();
402
406
 
403
407
  createConfig();
408
+ writeVersionFile(pkg.version);
404
409
 
405
410
  const isLinux = os.platform() === 'linux';
406
411
  const hasSystemd = isLinux && (() => { try { execSync('systemctl --version', { stdio: 'ignore' }); return true; } catch { return false; } })();
@@ -720,6 +725,14 @@ async function update() {
720
725
  }
721
726
  stepper.advance();
722
727
 
728
+ // Read release notes and write version before cleanup
729
+ let releaseNotes = '';
730
+ try {
731
+ const newPkg = JSON.parse(fs.readFileSync(path.join(extracted, 'package.json'), 'utf-8'));
732
+ releaseNotes = newPkg.releaseNotes || '';
733
+ } catch {}
734
+ writeVersionFile(latest.version);
735
+
723
736
  // Clean up
724
737
  fs.rmSync(tmpDir, { recursive: true, force: true });
725
738
 
@@ -736,6 +749,15 @@ async function update() {
736
749
 
737
750
  console.log(`\n ${c.blue}${c.bold}✔ Updated to v${latest.version}${c.reset}\n`);
738
751
 
752
+ if (releaseNotes) {
753
+ console.log(` ${c.bold}${c.white}What's new:${c.reset}`);
754
+ const notes = Array.isArray(releaseNotes) ? releaseNotes : [releaseNotes];
755
+ notes.forEach((note, i) => {
756
+ console.log(` ${c.dim}${i + 1}.${c.reset} ${note}`);
757
+ });
758
+ console.log('');
759
+ }
760
+
739
761
  if (daemonWasRunning) {
740
762
  if (isServiceActive()) {
741
763
  console.log(` ${c.blue}✔${c.reset} Daemon restarted with new version.\n`);
package/package.json CHANGED
@@ -1,6 +1,12 @@
1
1
  {
2
2
  "name": "fluxy-bot",
3
- "version": "0.5.44",
3
+ "version": "0.5.46",
4
+ "releaseNotes": [
5
+ "Worker and backend now survive systemd environments",
6
+ "Daemon auto-installs on Linux during init/start",
7
+ "Update flow stops daemon before applying files",
8
+ "Status command detects daemon state"
9
+ ],
4
10
  "description": "Self-hosted, self-evolving AI agent with its own dashboard.",
5
11
  "type": "module",
6
12
  "license": "MIT",
@@ -16,7 +16,8 @@ import { startFluxyAgentQuery, stopFluxyAgentQuery, type RecentMessage } from '.
16
16
  import { ensureFileDirs, saveAttachment, type SavedFile } from './file-saver.js';
17
17
  import { startViteDevServers, stopViteDevServers } from './vite-dev.js';
18
18
  import { startScheduler, stopScheduler } from './scheduler.js';
19
- import { execSync } from 'child_process';
19
+ import { execSync, spawn as cpSpawn } from 'child_process';
20
+ import os from 'os';
20
21
 
21
22
  const DIST_FLUXY = path.join(PKG_DIR, 'dist-fluxy');
22
23
 
@@ -534,6 +535,11 @@ export async function startSupervisor() {
534
535
  resetBackendRestarts();
535
536
  stopBackend().then(() => spawnBackend(backendPort));
536
537
  }
538
+ // Run deferred update if agent requested one
539
+ if (pendingUpdate) {
540
+ pendingUpdate = false;
541
+ runDeferredUpdate();
542
+ }
537
543
  return; // don't forward bot:done to client
538
544
  }
539
545
 
@@ -656,6 +662,26 @@ export async function startSupervisor() {
656
662
  // Track whether an agent query is active — file watcher defers to bot:done during turns
657
663
  let agentQueryActive = false;
658
664
  let pendingBackendRestart = false; // Set when file watcher fires during agent turn
665
+ let pendingUpdate = false; // Set when .update file is created during agent turn
666
+
667
+ // Run fluxy update in a separate systemd scope so it survives daemon stop/restart
668
+ function runDeferredUpdate() {
669
+ const cliPath = path.join(PKG_DIR, 'bin', 'cli.js');
670
+ log.info('Deferred update triggered — running fluxy update via systemd-run...');
671
+ try {
672
+ const child = cpSpawn('sudo', [
673
+ 'systemd-run', '--quiet',
674
+ '--unit=fluxy-update',
675
+ '--setenv=HOME=' + os.homedir(),
676
+ '--setenv=FLUXY_NODE_PATH=' + process.execPath,
677
+ '--setenv=FLUXY_REAL_HOME=' + os.homedir(),
678
+ process.execPath, cliPath, 'update',
679
+ ], { detached: true, stdio: 'ignore' });
680
+ child.unref();
681
+ } catch (err) {
682
+ log.error(`Deferred update failed: ${err instanceof Error ? err.message : err}`);
683
+ }
684
+ }
659
685
 
660
686
  // Spawn worker + backend
661
687
  spawnWorker(workerPort);
@@ -712,6 +738,16 @@ export async function startSupervisor() {
712
738
  try { fs.unlinkSync(path.join(workspaceDir, '.restart')); } catch {}
713
739
  scheduleBackendRestart('.restart trigger');
714
740
  }
741
+ if (filename === '.update') {
742
+ // Consume the trigger file
743
+ try { fs.unlinkSync(path.join(workspaceDir, '.update')); } catch {}
744
+ if (agentQueryActive) {
745
+ pendingUpdate = true;
746
+ log.info('Update requested — deferring until agent turn ends');
747
+ } else {
748
+ runDeferredUpdate();
749
+ }
750
+ }
715
751
  });
716
752
 
717
753
  // Tunnel
@@ -152,6 +152,28 @@ If a `<CRON_TASK_DETAIL>` block follows the CRON tag, it contains the full instr
152
152
 
153
153
  Notify your human only if importance is 7+ — otherwise log results silently.
154
154
 
155
+ ## Self-Update
156
+
157
+ **Check version:** `cat ~/.fluxy/VERSION` (current) vs `npm view fluxy-bot version` (latest).
158
+
159
+ **To update:** Create the trigger file `touch ~/.fluxy/workspace/.update` — the supervisor runs the update after your turn ends. You will
160
+ NOT die. Finish your turn normally.
161
+
162
+ **On PULSE:** Occasionally check for updates (not every pulse — once every few hours). If a new version exists:
163
+ 1. Read release notes: `npm view fluxy-bot releaseNotes --json`
164
+ 2. `touch ~/.fluxy/workspace/.update`
165
+ 3. Save to daily notes: "Updated from vX to vY" + notable changes
166
+ 4. Only <Message> the user if release notes contain something important (new feature, breaking change). Skip routine fixes.
167
+
168
+ **When user asks to update:**
169
+ 1. Check version, if already latest say so
170
+ 2. Otherwise read release notes, `touch ~/.fluxy/workspace/.update`
171
+ 3. ALWAYS send a <Message>:
172
+ "Updated to vX.Y.Z! Here's what's new:
173
+ 1. ...
174
+ 2. ...
175
+ 3. ..."
176
+
155
177
  ## Task Files — `tasks/`
156
178
 
157
179
  Complex cron tasks can have detailed instruction files in `tasks/{cron-id}.md`. The supervisor automatically injects the file content into your context when the cron fires.