Skip to content

Conversation

@shannah
Copy link
Owner

@shannah shannah commented Jan 19, 2026

No description provided.

shannah and others added 30 commits January 3, 2026 11:01
- Added RFC
- Disabled commands and services in branch versions
When updating we need to stop running services before install.  Then start services after update.
Removed services need to be uninstalled before update.
Provides callback interface for handling system tray menu actions in service management, enabling decoupled implementation of tray UI and service operations.
Implements system tray integration with popup menu for managing services, including start/stop controls, log viewing, and application lifecycle operations.
Adds thread-safe updateServices() method with balloon notifications for new errors and renames remove() to dispose() for proper resource cleanup.
shannah and others added 30 commits January 18, 2026 07:09
Add Helper application installation for service management during the
main installation process. The Helper provides system tray icon for
service status and user-friendly uninstallation capabilities.

- Add imports for Helper classes
- Add conditional call to installHelperApplication() after service setup
- Create installHelperApplication() method with platform-specific handling
- Create findJdeployFilesDirFromInstalledApp() to locate permanent .jdeploy-files
- Create findJdeployFilesRecursive() for macOS bundle search
- Create createHelperInstallationService() factory method

Helper installation is:
- Only triggered when services are defined
- Skipped for branch installations
- Non-blocking on failure (logs warning and continues)
After successful Helper installation, update the uninstall manifest to
include Helper entries so they are properly cleaned up during uninstall.

- Add updateManifestWithHelper() method that loads existing manifest,
  copies all entries to a new builder, adds Helper entries via
  HelperManifestHelper, and saves the updated manifest
- Call updateManifestWithHelper() after successful Helper installation
- Manifest update is best-effort; failures are logged but don't block
  installation since Helper was already installed successfully
Add utility class to detect and terminate running Helper processes:

- isHelperRunning(appName): Check if Helper is running via file lock
- terminateHelper(appName, timeoutMs): Graceful termination with fallback
- forceKillHelper(appName): Platform-specific force kill (pkill/taskkill)

Uses same file locking mechanism as TrayIconLock for detection.
Graceful termination creates shutdown signal file for Helper to detect.

Includes 22 unit tests covering detection logic, validation, and
lock file path generation.
Add service class to handle Helper updates during application updates:

- updateHelper(): Main method handling install/update/remove scenarios
  - Services exist + no Helper: Install new Helper
  - Services exist + Helper exists: Terminate, delete, reinstall
  - Services removed: Terminate and delete Helper
- deleteHelper(): Remove Helper executable, context dir, and parent dirs

Includes HelperUpdateResult class with UpdateType enum (INSTALLED,
UPDATED, REMOVED, NO_ACTION, FAILED) for detailed operation tracking.

Coordinates between HelperInstallationService and HelperProcessManager
to safely update Helper without leaving stale processes.

Includes 27 unit tests with mocked dependencies.
Add support for updating Helper applications during app updates:
- Move isUpdate flag to broader scope for use in Helper section
- Differentiate between fresh installs and updates for Helper handling
- Add updateHelperApplication() method using HelperUpdateService
- Add createHelperUpdateService() factory method
- Handle service removal scenario (removes Helper when services removed)
…Lock

Use consistent fully qualified package name format for lock files:
- Format: {md5(source)}.{sanitizedPackageName}.lock (or just {sanitizedPackageName}.lock if no source)
- Both HelperProcessManager and TrayIconLock now use identical naming
- Updated method signatures to use packageName/source instead of appName for lock operations
- Process killing still uses appName since that matches the process name

This ensures HelperProcessManager.isHelperRunning() correctly detects running Helpers.
Generates platform-specific cleanup scripts for Helper self-deletion:
- Unix: bash script with rm -rf, rmdir, and self-delete
- Windows: batch script with del, rmdir, and self-delete
- Scripts wait 2 seconds before cleanup to allow process exit
- Handles special character escaping for paths
- Supports detached process execution via nohup/start

Includes 30 unit tests for script content verification.
Adds a service class that orchestrates Helper self-deletion after uninstall
by coordinating with HelperCleanupScriptGenerator to generate and execute
platform-specific cleanup scripts.

Key features:
- scheduleHelperCleanup(appName, appDirectory) schedules Helper for deletion
- getHelperPath() resolves Helper path from jdeploy.launcher.path or HelperPaths
- helperExists() checks if Helper exists for an application
- scheduleCurrentHelperCleanup() for running Helper to delete itself
- Handles macOS .app bundle path resolution from launcher path

Also updates CLAUDE.md with git commit conventions.
Completes the uninstall functionality in BackgroundHelper with:
- Confirmation dialog before uninstall
- UninstallService integration for package cleanup
- HelperSelfDeleteService for Helper self-deletion
- Platform-appropriate RegistryOperations (JNA on Windows, no-op elsewhere)
- Proper error handling with user feedback

The Helper can now fully uninstall an application from the tray menu,
including cleaning up package files, registry entries, and itself.
Ensures BackgroundHelper can properly resolve application context needed
for uninstallation even when running offline:

- DefaultInstallationContext.applyContext() now handles null npmPackageVersion
  gracefully, skipping website URL setup which is only needed by installer UI
- Main.loadAppInfo() catches network failures in background helper mode,
  allowing Helper to start even when offline since it only needs app.xml info
- Added BackgroundHelperTest with 15 tests verifying context resolution:
  - getAppName() fallback chain (title -> packageName -> "Application")
  - getPackageName() fallback from settings to AppInfo
  - getSource() fallback with empty string treated as null
  - Typical Helper scenario validation
Implements graceful termination support so HelperProcessManager can
request the Helper to shut down without force killing.

The Helper now:
- Starts a daemon thread that polls for shutdown signal file every 500ms
- Signal file path: ~/.jdeploy/locks/{fullyQualifiedName}.shutdown
- When detected: stops tray controller, deletes signal file, exits cleanly

Path construction matches HelperProcessManager exactly:
- Uses MD5 hash of source for fully qualified name
- Same sanitization logic for package names

Added 9 new tests verifying:
- Signal file path generation with/without source
- Package name sanitization
- Path format matches HelperProcessManager
- Monitor state management
- HelperCopyService: Log all errors before throwing IOExceptions with
  detailed context (paths, error messages) for ditto, file copy, delete,
  and directory creation operations
- HelperInstallationService: Include helper paths in failure results
  when available for better debugging
- HelperUpdateService: Add granular error handling for each deletion
  step, with detailed warnings that don't block non-critical operations
- HelperSelfDeleteService: Include app name and helper path in all
  error messages for better traceability

Add comprehensive unit tests for error scenarios across all services.
Add HelperInstallationIntegrationTest with 4 test scenarios:
- testFreshInstallWithServices: Verifies complete Helper installation
  with directory creation, executable, context files, and manifest entries
- testFreshInstallWithoutServices: Verifies Helper is NOT created when
  no services are defined
- testBranchInstallSkipsHelper: Verifies branch installations skip
  Helper creation even with services
- testHelperInstallationFailureDoesNotBlockMainInstall: Verifies
  graceful failure handling without blocking main installation

Tests are platform-aware (macOS .app bundles vs Windows/Linux) and
tagged with @tag("integration") for filtering.
Add HelperUpdateIntegrationTest with 5 test scenarios:
- testUpdateWithServicesInBothVersions: Verifies old Helper replaced
  with new and .jdeploy-files updated to new version
- testUpdateAddingServices: Verifies Helper installed when services
  are added to an app that previously had none
- testUpdateRemovingServices: Verifies Helper deleted and directory
  cleaned up when services are removed
- testUpdateWithRunningHelper: Verifies running Helper is terminated
  before replacement using mocked HelperProcessManager
- testUpdateWithTerminationFailure: Verifies update proceeds with
  warning even when Helper termination fails

Tests are platform-aware and tagged with @tag("integration").
Add HelperUninstallIntegrationTest with 5 test scenarios:
- testUninstallFromHelper: Verifies uninstall flow and cleanup script
  generation with correct Helper paths
- testUninstallCleansUpHelperFiles: Verifies cleanup script creation,
  path content, and manual execution of cleanup logic
- testUninstallWithPartialFailure: Verifies Helper cleanup can proceed
  even when main uninstall has partial failures
- testHelperSelfDeleteServiceHandlesErrors: Verifies graceful error
  handling when script generation fails
- testCleanupScriptPathEscaping: Verifies paths with special characters
  are properly quoted in generated scripts

Tests verify both Windows batch and Unix bash script formats.
Tagged with @tag("integration") for filtering.
- Add detailed @param and @return Javadoc to HelperUpdateResult factory methods
- Add comprehensive method-level Javadoc to HelperCleanupScriptGenerator
- Add inline comments explaining script behavior and platform differences
Tests that pass null for appDirectory only work on macOS since
HelperPaths throws IllegalArgumentException on Windows/Linux.
Added platform checks to skip these tests on non-Mac platforms.
- Skip Unix script content tests on Windows (path escaping differs)
- Skip macOS app bundle resolution test on non-Mac platforms
The pom.xml uses ${maven.multiModuleProjectDirectory}/maven-repository to
locate the local repository. Without a .mvn directory, this variable
resolves to whichever directory Maven is invoked from. When release.sh
runs 'mvn clean package' from the cli/ directory, Maven looks for
cli/maven-repository instead of the root maven-repository.

Adding .mvn/ ensures Maven always resolves the project root correctly.
Tray icon is now only displayed in the background helper, not during
installation. Removed ServiceTrayController and related handler methods
from DefaultInstallationForm.
Add support for helper actions defined in package.json under
jdeploy.helper.actions. Helper actions allow users to quickly open
URLs, custom protocol handlers, or files from the system tray menu
and ServiceManagementPanel.

Configuration format:
```json
{
  "jdeploy": {
    "helper": {
      "actions": [
        { "label": "Open Dashboard", "description": "...", "url": "https://..." }
      ]
    }
  }
}
```

Changes:
- Add HelperAction model class in shared module
- Add HelperActionExecutor service to handle URL/file opening
- Parse helper actions from package.json in NPMPackageVersion
- Display helper actions before services in tray menu
- Display helper actions as "Quick Actions" in ServiceManagementPanel
- Add unit tests for helper action parsing
Add a new "Helper Actions" section to the jDeploy project editor that
allows users to manage helper actions through an editable table.

The panel appears after "CLI Commands" in the navigation and provides:
- Editable table with Label, Description, and URL columns
- Add/Remove buttons for managing actions
- Help text explaining supported URL types (web URLs, custom protocols, file paths)
- Basic validation (label and URL required, description optional)

Configuration is stored in package.json under jdeploy.helper.actions.
- Tab moves to next cell, wrapping to next row
- Shift+Tab moves to previous cell, wrapping to previous row
- Enter moves to next row in same column
- Automatically starts editing and focuses the cell editor
…ntroller

Previously, the background helper was only installed when the app had
commands implementing service_controller. Now it installs whenever the
app has any commands defined. Additionally, the helper is no longer
removed during updates - removal only occurs during uninstall.
Changed SetupClaudeService to install jDeploy instructions as a Claude Code
skill at .claude/skills/setup-jdeploy.md instead of appending to CLAUDE.md.
This is less intrusive and follows best practices for Claude Code skills.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants