The migration was correct as v4.0→v4.1. Config version goes from 4.0 to 4.1
when thresholds are moved to actions. The original error was not the migration
but the ups-handler.ts bug (already fixed in v4.2.1).
User's config shows version "4.1" with actions already present, confirming
the migration ran successfully.
The migration was incorrectly named as v4.0→v4.1 but was actually performing
the v4.1→v4.2 migration (moving thresholds from UPS-level to action-level).
This meant users upgrading from v4.1 would not get their configs migrated.
Changes:
- Renamed migration file from migration-v4.0-to-v4.1.ts to migration-v4.1-to-v4.2.ts
- Updated class name from MigrationV4_0ToV4_1 to MigrationV4_1ToV4_2
- Updated fromVersion from '4.0' to '4.1'
- Updated toVersion from '4.1' to '4.2'
- Updated shouldRun() to check for config.version === '4.1'
- Updated all imports and exports to reference the new class name
- Updated comments and log messages to reflect v4.1→v4.2 migration
- Remove call to gatherThresholdSettings in runAddProcess
- Delete entire gatherThresholdSettings method
- Thresholds are now configured per-action in gatherActionSettings
Fixes: Cannot read properties of undefined (reading 'battery')
- Add proper ES6 imports at top of file for theme, symbols, colors
- Remove all require() calls that were causing 'require is not defined' errors
- Daemon now starts properly with modernized logging intact
- Modernize periodic status update with logger.logTable() and color-coded battery/runtime
- Modernize configuration loaded display with tables for UPS devices and groups
- Enhance power status change notifications with better colors and timestamps
- Modernize shutdown monitoring with real-time table display of UPS status
- Add color-coded CRITICAL indicators for emergency conditions
- Improve visual hierarchy with appropriate box styles (info, warning, error, success)
- Ensure consistent theming across all daemon log output
- Modernize ups list command with logger.logTable()
- Modernize group list command with logger.logTable()
- Completely rewrite config show with tables and proper box styling
- Add professional column definitions with themed colors
- Replace all manual table formatting (padEnd, pipe separators)
- Improve visual hierarchy with appropriate box styles (info, warning, success)
- Ensure consistent theming across all CLI commands
- Add version display at the top of status output
- Check for available updates and notify user
- Show "Up to date" or "Update available" with version
- Display before service and UPS status information
- Improves user awareness of software version and updates
Bumps version to 4.1.4
- Add process.stdin.destroy() after rl.close() in all interactive commands
to properly release stdin and allow process to exit cleanly
- Replace raw console.log with logger methods throughout CLI handlers
- Convert manual box drawing to logger.logBox() in daemon.ts
- Standardize menu formatting with logger.info() and logger.dim()
- Improve migration output to only show when migrations actually run
Fixes issue where process would not exit after "Setup complete!" message
due to stdin keeping the event loop alive.
Move power status value interpretation from hardcoded logic to OID set configuration.
Each UPS model now defines its own value mappings (e.g., CyberPower: 2=online, 3=onBattery).
Fixes incorrect status display where UPS showed "On Battery" when actually online.
Changes:
- Add POWER_STATUS_VALUES to IOidSet interface
- Define value mappings for all UPS models (cyberpower, apc, eaton, tripplite, liebert)
- Refactor determinePowerStatus() to use OID set mappings instead of hardcoded values
- CyberPower now correctly interprets value 2 as online (was incorrectly onBattery)
Removed the last remaining ugly ASCII boxes:
- Version info box (┌─┐│└┘) that appeared at top
- Async version check box that ended randomly in middle
- Configuration error box
Now status output is 100% clean and beautiful with just colored text:
● Service: active (running)
PID: 9120 Memory: 45.7M CPU: 190ms
UPS Devices (2):
⚠ Test UPS (SNMP v1) - On Battery
Battery: 100% ✓ Runtime: 48 min
Host: 192.168.187.140:161
◯ Test UPS (SNMP v3) - Unknown
Battery: 0% ⚠ Runtime: 0 min
Host: 192.168.187.140:161
No boxes, just beautiful colored output with symbols!
Bumped to v4.1.0 to mark completion of beautiful CLI feature.
The version check was comparing "4.0.8" (no prefix) with "v4.0.8"
(with prefix), causing it to always think an update was available.
Now both versions are normalized to have the "v" prefix before
comparison, so "Already up to date!" works correctly.
Now `nupst update` checks current version against latest release before
downloading anything.
Behavior:
- Fetches latest version from Gitea API
- Compares with current version
- Shows "Already up to date!" if versions match
- Only downloads/installs if newer version available
Example output when up to date:
Checking for updates...
Current version: v4.0.8
Latest version: v4.0.8
✓ Already up to date!
The update command was still using v3 logic (git pull, setup.sh) which
doesn't work for v4 binary distribution.
Now it simply:
1. Downloads install.sh from main branch
2. Runs it (handles download, stop, replace, restart automatically)
This is much simpler and matches how v4 is distributed. No more git,
no more setup.sh, just download the latest binary.
Replaced all ASCII box characters (┌─┐│└┘) with modern, clean colored
output using the existing color theme and symbols.
Changes in ts/systemd.ts:
- displayServiceStatus(): Parse systemctl output and show key info
with colored symbols (● for running, ○ for stopped)
- displaySingleUpsStatus(): Clean output with battery/runtime colors
- Green >60%, yellow 30-60%, red <30% for battery
- Power status with colored symbols and text
- Clean indented layout without boxes
Example new output:
● Service: active (running)
PID: 7606 Memory: 41.5M CPU: 279ms
UPS Devices (2):
● Test UPS (SNMP v1) - Online
Battery: 100% ✓ Runtime: 48 min
Host: 192.168.187.140:161
Much cleaner and more readable than ASCII boxes!
The previous migration only checked for upsList field, but saveConfig()
strips upsList when saving, creating a race condition. If the daemon
restarted with a partially-migrated config (upsDevices with flat structure),
the migration wouldn't run because it only looked for upsList.
Now shouldRun() also detects:
- upsDevices with flat structure (host at top level, no snmp object)
And migrate() handles both:
- config.upsList (pure v3)
- config.upsDevices with flat structure (partially migrated)
This fixes the "Cannot read properties of undefined (reading 'host')"
error that occurred when configs had upsDevices but flat structure.
Interactive mode was causing issues with automated testing and the
nupst update command (failed with /dev/tty errors). Since users
running curl|bash have already decided to install, prompts add no
value and only create friction.
Changes:
- Removed -y/--yes flag (no longer needed)
- Removed all interactive confirmation prompts
- Removed terminal detection logic (/dev/tty handling)
- Updated README to remove all -y flag references
- Simplified installation examples
Benefits:
- Works in all environments (piped, non-interactive, containers)
- Fixes nupst update command
- Cleaner user experience
- Matches standard install script patterns (homebrew, rustup, etc.)
The v3→v4 migration was only renaming upsList to upsDevices without
transforming the device structure. V3 had a flat structure with SNMP
fields directly on the device object, while v4 expects a nested 'snmp'
object.
This commit fixes the migration to:
- Move host, port, community, version, etc. into nested snmp object
- Convert version from string to number
- Add default timeout (5000ms)
- Create thresholds object with defaults
- Preserve all SNMPv1, v2c, and v3 authentication fields
Also includes install.sh fix for better non-interactive handling.
- Create abstract BaseMigration class with order, shouldRun(), migrate()
- Add MigrationRunner to execute migrations in order
- Add Migration v1→v2 (snmp → upsDevices)
- Add Migration v3→v4 (upsList → upsDevices)
- Update INupstConfig with version field
- Update loadConfig() to run migrations automatically
- Update saveConfig() to ensure version field and remove legacy fields
- Update Docker test scripts to use real UPS data from .nogit/env.json
- Remove colors.bright (not available in @std/fmt/colors)
Config migrations allow users to jump versions (e.g., v1→v4) with all
intermediate migrations running automatically. Version field tracks
config format for future migrations.
Major improvements:
- Created color theme system (ts/colors.ts) with ANSI colors
- Enhanced logger with colors, table formatting, and styled boxes
- Fixed daemon exit bug - now stays running when no UPS configured
- Added config hot-reload with file watcher for live updates
- Beautified CLI help output with color-coded commands
- Added showcase test demonstrating all output features
- Fixed ANSI code handling for perfect table/box alignment
Features:
- Color-coded messages (success=green, error=red, warning=yellow, info=cyan)
- Status symbols (●○◐◯ for running/stopped/starting/unknown)
- Battery level colors (green>60%, yellow 30-60%, red<30%)
- Table formatting with auto-sizing and column alignment
- Styled boxes (success, error, warning, info styles)
- Hot-reload: daemon watches config file and reloads automatically
- Idle mode: daemon stays alive when no devices, checks periodically
Daemon improvements:
- No longer exits when no UPS devices configured
- Enters idle monitoring loop waiting for config
- File watcher detects config changes in real-time
- Auto-reloads and starts monitoring when devices added
- Logs warnings instead of errors for missing devices
Technical fixes:
- Strip ANSI codes when calculating text width for alignment
- Use visible length for padding calculations in tables and boxes
- Properly handle colored text in table cells and box lines
Breaking changes: None (backward compatible)
Previously only checked 'is-active' which missed failed/stopped services.
Now checks 'is-enabled' OR 'is-active' to ensure service file gets updated
during v3→v4 migration regardless of service state.
Critical fixes for v3→v4 migration:
1. install.sh: Auto-update systemd service file during migration
- Calls 'nupst service enable' before restarting service
- Only when migrating from v3 (OLD_NODE_INSTALL=1)
- Ensures service file has correct v4 paths
2. ts/systemd.ts: Fix hardcoded v3 paths in service template
- ExecStart: /opt/nupst/bin/nupst daemon-start (v3, broken)
→ /usr/local/bin/nupst service start-daemon (v4, correct)
- Description: Updated to 'Deno-powered UPS Monitoring Tool'
- Added RestartSec=10 (prevent rapid restart loops)
- Removed NODE_ENV=production (not needed for Deno)
- WorkingDirectory: /tmp → /opt/nupst
Without these fixes:
- Service fails to start after migration
- Service file points to non-existent /opt/nupst/bin/nupst
- Users must manually run 'nupst service enable'
Discovered via Docker migration testing in test/manualdocker/
- Checks if release already exists for the tag
- Automatically deletes conflicting release if found
- Prevents duplicate/stale releases when recreating tags
- Ensures fresh binaries when tag is recreated
This fixes the issue where recreating a tag would keep old
release with outdated binaries.
- Replace hardcoded version in 00_commitinfo_data.ts
- Now dynamically imports deno.json and reads version
- Version will auto-update when deno.json is changed
- Fixes version showing 3.1.2 instead of 4.0.0
test: add Docker test scripts for v3→v4 migration
- 01-setup-v3-container.sh: Creates systemd container with v3
- 02-test-v3-to-v4-migration.sh: Tests migration (now fixed)
- 03-cleanup.sh: Removes test container
- README.md: Complete documentation
Tested: Version now correctly shows 4.0.0
- Changed back to single artifact containing all binaries
- Named 'nupst-binaries.zip' to clarify it's a ZIP container
- Contains all 5 platform binaries + SHA256SUMS.txt
- Split single 'nupst-binaries' artifact into 6 individual artifacts
- Each platform binary now shows as separate downloadable item in UI
- Artifacts: nupst-linux-x64, nupst-linux-arm64, nupst-macos-x64,
nupst-macos-arm64, nupst-windows-x64.exe, SHA256SUMS.txt
- actions/upload-artifact@v4 not supported on Gitea
- Error: GHES (GitHub Enterprise Server) compatibility issue
- Using v3 which is compatible with Gitea Actions
- Remove conditional from build-all job in ci.yml
- Previously only ran on main branch and tags
- Now runs on every commit to any branch
- Allows testing binaries from feature branches via artifacts API
- Remove async from functions that don't use await
- Change return types from Promise<void> to void for synchronous functions
- Fixes all 8 require-await lint warnings
- Reduces total lint warnings from 63 to 55
- Clean old binaries from dist/binaries before each build
- Automatically delete old releases, keeping only the last 3
- Prevents accumulation of stale binaries and release storage bloat
Enhanced install.sh to properly handle updates and migrations:
**Update Detection & Service Management:**
- Detect old Node.js-based installations (v3.x) via package.json/node_modules
- Stop running service before updating binary
- Restart service after successful update if it was running
- Preserve /etc/nupst/config.json during updates
**Migration from v3.x to v4.0:**
- Clean up old Node.js installation files:
- node_modules/, vendor/, dist_ts/ directories
- package.json, package-lock.json, pnpm-lock.yaml
- tsconfig.json, setup.sh, bin/ directory
- Inform user about migration with helpful feedback
- Link to migration guide documentation
**User Experience Improvements:**
- Show different messages for new installs vs updates
- Inform about v3.x → v4.0 migration when detected
- Display migration guide link for old installations
- Show service restart status
- Provide context-aware next steps based on config presence
**Safety Features:**
- Ask for confirmation before replacing existing installation (interactive mode)
- Preserve user configuration in /etc/nupst/
- Handle service state properly (stop → update → restart)
- Graceful cleanup with error suppression (|| true)
This ensures seamless updates from any version (including v3.x Node.js installs)
to v4.0+ Deno-based binaries without manual intervention or data loss.
Comprehensive type safety improvements across all CLI handlers and daemon:
**Error handling type fixes:**
- Add 'error instanceof Error' checks before accessing error.message throughout
- Fix all error/retryError/stdError/upsError type assertions
- Replace direct error.message with proper type guards
**Switch case improvements:**
- Wrap case block declarations in braces to satisfy deno-lint
- Fix no-case-declarations warnings in CLI command handlers
**Null/undefined safety:**
- Add checks for config.snmp and config.thresholds before access
- Fix IUpsStatus lastStatusChange to handle undefined with default value
- Add proper null checks in legacy configuration paths
**Type annotations:**
- Add explicit type annotations to lambda parameters (groupId, updateAvailable, etc.)
- Add TUpsModel type cast for 'cyberpower' default
- Import and use INupstConfig type where needed
**Parameter type fixes:**
- Fix implicit 'any' type errors in array callbacks
- Add type annotations to filter/find/map parameters
Files modified:
- ts/cli.ts: config.snmp/thresholds null checks, unused error variable fixes
- ts/cli/group-handler.ts: 4 error.message fixes + 2 parameter type annotations
- ts/cli/service-handler.ts: 3 error.message fixes
- ts/cli/ups-handler.ts: 5 error.message fixes + config checks + TUpsModel import
- ts/daemon.ts: 8 error.message fixes + IUpsStatus lastStatusChange fix + updateAvailable type
- ts/nupst.ts: 1 error.message fix
- ts/systemd.ts: 5 error.message fixes + parameter type annotation
All tests passing (3/3 SNMP tests + 10/10 logger tests)
Type check: ✓ No errors
- Add Buffer import from node:buffer to manager.ts and types.ts
- Fix error handling type assertions (error/retryError/stdError as unknown)
- Add explicit type annotation to byte parameter in isPrintableAscii check
- All tests now passing (3 SNMP tests + 10 logger tests)