mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
docs: rebrand Happy to HAPI and add component documentation
This commit rebrands the project from "Happy" to "HAPI" throughout the codebase, including documentation, comments, logs, and tool references. It also adds comprehensive README files for the server and web components, clarifies the monorepo structure in AGENTS.md and root README.md, and removes the outdated roadmap.md file. Changes include: - Rebrand references from Happy to HAPI in CLI, server, and web components - MCP tool names updated from mcp__happy__ to mcp__hapi__ - Process/service names updated consistently - New server/README.md with deployment and configuration guide - New web/README.md with stack and development instructions - Updated root README.md with quickstart guide - Updated AGENTS.md with cleaner structure documentation - Removed cli/roadmap.md (now superseded by documentation)
This commit is contained in:
+19
-19
@@ -1,12 +1,12 @@
|
||||
# Happy CLI Daemon: Control Flow and Lifecycle
|
||||
# HAPI CLI Daemon: Control Flow and Lifecycle
|
||||
|
||||
The daemon is a persistent background process that manages Happy sessions, enables remote control from the mobile app, and handles auto-updates when the CLI version changes.
|
||||
The daemon is a persistent background process that manages HAPI sessions, enables remote control from the mobile app, and handles auto-updates when the CLI version changes.
|
||||
|
||||
## 1. Daemon Lifecycle
|
||||
|
||||
### Starting the Daemon
|
||||
|
||||
Command: `happy daemon start`
|
||||
Command: `hapi daemon start`
|
||||
|
||||
Control Flow:
|
||||
1. `src/index.ts` receives `daemon start` command
|
||||
@@ -23,7 +23,7 @@ Control Flow:
|
||||
- HTTP server: starts on random port for local CLI control (list, stop, spawn)
|
||||
- WebSocket: establishes persistent connection to backend via `ApiMachineClient`
|
||||
- RPC registration: exposes `spawn-happy-session`, `stop-session`, `requestShutdown` handlers
|
||||
- Heartbeat loop: every 60s (or HAPPY_DAEMON_HEARTBEAT_INTERVAL) checks for version updates and prunes dead sessions
|
||||
- Heartbeat loop: every 60s (or HAPI_DAEMON_HEARTBEAT_INTERVAL) checks for version updates and prunes dead sessions
|
||||
5. Awaits shutdown promise which resolves when:
|
||||
- OS signal received (SIGINT/SIGTERM)
|
||||
- HTTP `/stop` endpoint called
|
||||
@@ -40,7 +40,7 @@ Control Flow:
|
||||
|
||||
### Version Mismatch Auto-Update
|
||||
|
||||
The daemon detects when `npm upgrade happy-coder` occurs:
|
||||
The daemon detects when `npm upgrade hapi` occurs:
|
||||
1. Heartbeat reads package.json from disk
|
||||
2. Compares `JSON.parse(package.json).version` with compiled `configuration.currentCliVersion`
|
||||
3. If mismatch detected:
|
||||
@@ -52,7 +52,7 @@ The daemon detects when `npm upgrade happy-coder` occurs:
|
||||
|
||||
### Stopping the Daemon
|
||||
|
||||
Command: `happy daemon stop`
|
||||
Command: `hapi daemon stop`
|
||||
|
||||
Control Flow:
|
||||
1. `stopDaemon()` in `controlClient.ts` reads daemon.state.json
|
||||
@@ -74,10 +74,10 @@ Initiated by mobile app via backend RPC:
|
||||
2. `ApiMachineClient` invokes `spawnSession()` handler
|
||||
3. `spawnSession()`:
|
||||
- Creates directory if needed
|
||||
- Spawns detached Happy process with `--hapi-starting-mode remote --started-by daemon`
|
||||
- Spawns detached HAPI process with `--hapi-starting-mode remote --started-by daemon`
|
||||
- Adds to `pidToTrackedSession` map
|
||||
- Sets up 10-second awaiter for session webhook
|
||||
4. New Happy process:
|
||||
4. New HAPI process:
|
||||
- Creates session with backend, receives `happySessionId`
|
||||
- Calls `notifyDaemonSessionStarted()` to POST to daemon's `/session-started`
|
||||
5. Daemon updates tracking with `happySessionId`, resolves awaiter
|
||||
@@ -85,10 +85,10 @@ Initiated by mobile app via backend RPC:
|
||||
|
||||
### Terminal-Spawned Sessions
|
||||
|
||||
User runs `happy` directly:
|
||||
User runs `hapi` directly:
|
||||
1. CLI auto-starts daemon if configured
|
||||
2. Happy process calls `notifyDaemonSessionStarted()`
|
||||
3. Daemon receives webhook, creates `TrackedSession` with `startedBy: 'happy directly...'`
|
||||
2. HAPI process calls `notifyDaemonSessionStarted()`
|
||||
3. Daemon receives webhook, creates `TrackedSession` with `startedBy: 'hapi directly...'`
|
||||
4. Session tracked for health monitoring
|
||||
|
||||
### Session Termination
|
||||
@@ -111,14 +111,14 @@ Local HTTP server (127.0.0.1 only) provides:
|
||||
|
||||
### Doctor Command
|
||||
|
||||
`happy doctor` uses `ps aux | grep` to find all Happy processes:
|
||||
`hapi doctor` uses `ps aux | grep` to find all HAPI processes:
|
||||
- Production: matches `happy.mjs`, `happy-coder`, `dist/index.mjs`
|
||||
- Development: matches `tsx.*src/index.ts`
|
||||
- Categorizes by command args: daemon, daemon-spawned, user-session, doctor
|
||||
|
||||
### Clean Runaway Processes
|
||||
|
||||
`happy doctor clean`:
|
||||
`hapi doctor clean`:
|
||||
1. `findRunawayHappyProcesses()` filters for likely orphans
|
||||
2. `killRunawayHappyProcesses()`:
|
||||
- Sends SIGTERM
|
||||
@@ -178,7 +178,7 @@ I do not like how
|
||||
|
||||
# Machine Sync Architecture - Separated Metadata & Daemon State
|
||||
|
||||
> Direct-connect note: the “server” is `happy-bot` (not `happy-server`), payloads are plain JSON (no base64/encryption),
|
||||
> Direct-connect note: the “server” is `hapi-server`, payloads are plain JSON (no base64/encryption),
|
||||
> and authentication uses `CLI_API_TOKEN` (REST `Authorization: Bearer ...` + Socket.IO `handshake.auth.token`).
|
||||
|
||||
## Data Structure (Similar to Session's metadata + agentState)
|
||||
@@ -222,7 +222,7 @@ Checks if machine ID exists in settings:
|
||||
"platform": "darwin",
|
||||
"happyCliVersion": "1.0.0",
|
||||
"homeDir": "/Users/john",
|
||||
"happyHomeDir": "/Users/john/.happy"
|
||||
"happyHomeDir": "/Users/john/.config/hapi"
|
||||
},
|
||||
"daemonState": {
|
||||
"status": "running",
|
||||
@@ -318,16 +318,16 @@ socket.emit('machine-update-metadata', {
|
||||
"platform": "darwin",
|
||||
"happyCliVersion": "1.0.1",
|
||||
"homeDir": "/Users/john",
|
||||
"happyHomeDir": "/Users/john/.happy"
|
||||
"happyHomeDir": "/Users/john/.config/hapi"
|
||||
},
|
||||
"expectedVersion": 1
|
||||
}, callback)
|
||||
```
|
||||
|
||||
## 5. Mini App RPC Calls (via happy-bot)
|
||||
## 5. Mini App RPC Calls (via hapi-server)
|
||||
|
||||
The Telegram Mini App calls REST endpoints on `happy-bot` (for example `POST /api/machines/:id/spawn`).
|
||||
`happy-bot` then relays those requests to the daemon via Socket.IO `rpc-request` on the `/cli` namespace.
|
||||
The Telegram Mini App calls REST endpoints on `hapi-server` (for example `POST /api/machines/:id/spawn`).
|
||||
`hapi-server` then relays those requests to the daemon via Socket.IO `rpc-request` on the `/cli` namespace.
|
||||
|
||||
RPC method naming (machine-scoped) uses a `${machineId}:` prefix, for example:
|
||||
- `${machineId}:spawn-happy-session`
|
||||
|
||||
@@ -32,7 +32,7 @@ async function daemonPost(path: string, body?: any): Promise<{ error?: string }
|
||||
}
|
||||
|
||||
try {
|
||||
const timeout = process.env.HAPPY_DAEMON_HTTP_TIMEOUT ? parseInt(process.env.HAPPY_DAEMON_HTTP_TIMEOUT) : 10_000;
|
||||
const timeout = process.env.HAPI_DAEMON_HTTP_TIMEOUT ? parseInt(process.env.HAPI_DAEMON_HTTP_TIMEOUT) : 10_000;
|
||||
const response = await fetch(`http://127.0.0.1:${state.httpPort}${path}`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
@@ -90,7 +90,7 @@ export async function stopDaemonHttp(): Promise<void> {
|
||||
|
||||
/**
|
||||
* The version check is still quite naive.
|
||||
* For instance we are not handling the case where we upgraded happy,
|
||||
* For instance we are not handling the case where we upgraded hapi,
|
||||
* the daemon is still running, and it recieves a new message to spawn a new session.
|
||||
* This is a tough case - we need to somehow figure out to restart ourselves,
|
||||
* yet still handle the original request.
|
||||
@@ -113,7 +113,7 @@ export async function stopDaemonHttp(): Promise<void> {
|
||||
* Not just a boolean.
|
||||
*
|
||||
* We can destructure the response on the caller for richer output.
|
||||
* For instance when running `happy daemon status` we can show more information.
|
||||
* For instance when running `hapi daemon status` we can show more information.
|
||||
*/
|
||||
export async function checkIfDaemonRunningAndCleanupStaleState(): Promise<boolean> {
|
||||
const state = await readDaemonState();
|
||||
@@ -164,7 +164,7 @@ export async function isDaemonRunningCurrentlyInstalledHappyVersion(): Promise<b
|
||||
|
||||
// PREVIOUS IMPLEMENTATION - Keeping this commented in case we need it
|
||||
// Kirill does not understand how the upgrade of npm packages happen and whether
|
||||
// we will get a new path or not when happy-coder is upgraded globally.
|
||||
// we will get a new path or not when hapi is upgraded globally.
|
||||
// If reading package.json doesn't work correctly after npm upgrades,
|
||||
// we can revert to spawning a process (but should add timeout and cleanup!)
|
||||
/*
|
||||
@@ -238,4 +238,4 @@ async function waitForProcessDeath(pid: number, timeout: number): Promise<void>
|
||||
}
|
||||
}
|
||||
throw new Error('Process did not die within timeout');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
* and the daemon will not work properly!
|
||||
*
|
||||
* The integration test environment uses .env.integration-test which sets:
|
||||
* - HAPPY_HOME_DIR=~/.happy-dev-test (DIFFERENT from dev's ~/.happy-dev!)
|
||||
* - HAPPY_BOT_URL=http://localhost:3006 (local happy-bot)
|
||||
* - CLI_API_TOKEN=... (must match the bot)
|
||||
* - HAPI_HOME_DIR=~/.hapi-dev-test (DIFFERENT from dev's ~/.hapi-dev!)
|
||||
* - HAPI_BOT_URL=http://localhost:3006 (local hapi-server)
|
||||
* - CLI_API_TOKEN=... (must match the server)
|
||||
*/
|
||||
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
@@ -136,7 +136,7 @@ describe.skipIf(!await isServerHealthy())('Daemon Integration Tests', { timeout:
|
||||
expect(sessions).toHaveLength(1);
|
||||
|
||||
const tracked = sessions[0];
|
||||
expect(tracked.startedBy).toBe('happy directly - likely by user from terminal');
|
||||
expect(tracked.startedBy).toBe('hapi directly - likely by user from terminal');
|
||||
expect(tracked.happySessionId).toBe('test-session-123');
|
||||
expect(tracked.pid).toBe(99999);
|
||||
});
|
||||
@@ -192,7 +192,7 @@ describe.skipIf(!await isServerHealthy())('Daemon Integration Tests', { timeout:
|
||||
});
|
||||
|
||||
it('should track both daemon-spawned and terminal sessions', async () => {
|
||||
// Spawn a real happy process that looks like it was started from terminal
|
||||
// Spawn a real hapi process that looks like it was started from terminal
|
||||
const terminalHappyProcess = spawnHappyCLI([
|
||||
'--hapi-starting-mode', 'remote',
|
||||
'--started-by', 'terminal'
|
||||
@@ -202,7 +202,7 @@ describe.skipIf(!await isServerHealthy())('Daemon Integration Tests', { timeout:
|
||||
stdio: 'ignore'
|
||||
});
|
||||
if (!terminalHappyProcess || !terminalHappyProcess.pid) {
|
||||
throw new Error('Failed to spawn terminal happy process');
|
||||
throw new Error('Failed to spawn terminal hapi process');
|
||||
}
|
||||
// Give time to start & report itself
|
||||
await new Promise(resolve => setTimeout(resolve, 5_000));
|
||||
@@ -223,7 +223,7 @@ describe.skipIf(!await isServerHealthy())('Daemon Integration Tests', { timeout:
|
||||
);
|
||||
|
||||
expect(terminalSession).toBeDefined();
|
||||
expect(terminalSession.startedBy).toBe('happy directly - likely by user from terminal');
|
||||
expect(terminalSession.startedBy).toBe('hapi directly - likely by user from terminal');
|
||||
|
||||
expect(daemonSession).toBeDefined();
|
||||
expect(daemonSession.startedBy).toBe('daemon');
|
||||
@@ -397,9 +397,9 @@ describe.skipIf(!await isServerHealthy())('Daemon Integration Tests', { timeout:
|
||||
* 7. New daemon starts, reads daemon.state.json, sees old version != its compiled version
|
||||
* 8. New daemon calls stopDaemon() to kill old daemon, then takes over
|
||||
*
|
||||
* This simulates what happens during `npm upgrade happy-coder`:
|
||||
* This simulates what happens during `npm upgrade hapi`:
|
||||
* - Running daemon has OLD version loaded in memory (configuration.currentCliVersion)
|
||||
* - npm replaces node_modules/happy-coder/ with NEW version files
|
||||
* - npm replaces node_modules/hapi/ with NEW version files
|
||||
* - package.json on disk now has NEW version
|
||||
* - Daemon reads package.json, detects mismatch, triggers self-update
|
||||
* - Key difference: npm atomically replaces the entire module directory, while
|
||||
@@ -451,7 +451,7 @@ describe.skipIf(!await isServerHealthy())('Daemon Integration Tests', { timeout:
|
||||
|
||||
// The daemon should automatically detect the version mismatch and restart itself
|
||||
// We check once per minute, wait for a little longer than that
|
||||
await new Promise(resolve => setTimeout(resolve, parseInt(process.env.HAPPY_DAEMON_HEARTBEAT_INTERVAL || '30000') + 10_000));
|
||||
await new Promise(resolve => setTimeout(resolve, parseInt(process.env.HAPI_DAEMON_HEARTBEAT_INTERVAL || '30000') + 10_000));
|
||||
|
||||
// Check that the daemon is running with the new version
|
||||
const finalState = await readDaemonState();
|
||||
@@ -471,7 +471,7 @@ describe.skipIf(!await isServerHealthy())('Daemon Integration Tests', { timeout:
|
||||
|
||||
// TODO: Add a test to see if a corrupted file will work
|
||||
|
||||
// TODO: Test npm uninstall scenario - daemon should gracefully handle when happy-coder is uninstalled
|
||||
// TODO: Test npm uninstall scenario - daemon should gracefully handle when hapi is uninstalled
|
||||
// Current behavior: daemon tries to spawn new daemon on version mismatch but dist/index.mjs is gone
|
||||
// Expected: daemon should detect missing entrypoint and either exit cleanly or at minimum not respawn infinitely
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@ import psList from 'ps-list';
|
||||
import spawn from 'cross-spawn';
|
||||
|
||||
/**
|
||||
* Find all Happy CLI processes (including current process)
|
||||
* Find all HAPI CLI processes (including current process)
|
||||
*/
|
||||
export async function findAllHappyProcesses(): Promise<Array<{ pid: number, command: string, type: string }>> {
|
||||
try {
|
||||
@@ -20,7 +20,7 @@ export async function findAllHappyProcesses(): Promise<Array<{ pid: number, comm
|
||||
const cmd = proc.cmd || '';
|
||||
const name = proc.name || '';
|
||||
|
||||
// Check if it's a Happy process
|
||||
// Check if it's a HAPI process
|
||||
const isHappyBinary = name === 'hapi' || name === 'hapi.exe' || /\bhapi(\.exe)?\b/.test(cmd);
|
||||
const isHappy = name.includes('happy') ||
|
||||
name === 'node' && (cmd.includes('happy-cli') || cmd.includes('dist/index.mjs')) ||
|
||||
@@ -59,7 +59,7 @@ export async function findAllHappyProcesses(): Promise<Array<{ pid: number, comm
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all runaway Happy CLI processes that should be killed
|
||||
* Find all runaway HAPI CLI processes that should be killed
|
||||
*/
|
||||
export async function findRunawayHappyProcesses(): Promise<Array<{ pid: number, command: string }>> {
|
||||
const allProcesses = await findAllHappyProcesses();
|
||||
@@ -80,7 +80,7 @@ export async function findRunawayHappyProcesses(): Promise<Array<{ pid: number,
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill all runaway Happy CLI processes
|
||||
* Kill all runaway HAPI CLI processes
|
||||
*/
|
||||
export async function killRunawayHappyProcesses(): Promise<{ killed: number, errors: Array<{ pid: number, error: string }> }> {
|
||||
const runawayProcesses = await findRunawayHappyProcesses();
|
||||
|
||||
@@ -10,6 +10,6 @@ export async function install(): Promise<void> {
|
||||
throw new Error('Daemon installation requires sudo privileges. Please run with sudo.');
|
||||
}
|
||||
|
||||
logger.info('Installing Happy CLI daemon for macOS...');
|
||||
logger.info('Installing HAPI CLI daemon for macOS...');
|
||||
await installMac();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* Installation script for Happy daemon using macOS LaunchDaemons
|
||||
* Installation script for HAPI daemon using macOS LaunchDaemons
|
||||
*
|
||||
* NOTE: This installation method is currently NOT USED in favor of auto-starting
|
||||
* the daemon when the user runs the happy command.
|
||||
* the daemon when the user runs the hapi command.
|
||||
*
|
||||
* Why we're not using this approach:
|
||||
* 1. Installing a LaunchDaemon requires sudo permissions, which users might not be comfortable with
|
||||
* 2. We assume users will run happy frequently (every time they open their laptop)
|
||||
* 2. We assume users will run hapi frequently (every time they open their laptop)
|
||||
* 3. The auto-start approach provides the same functionality without requiring elevated permissions
|
||||
*
|
||||
* This code is kept for potential future use if we decide to offer system-level installation as an option.
|
||||
@@ -18,7 +18,7 @@ import { logger } from '@/ui/logger';
|
||||
import { trimIdent } from '@/utils/trimIdent';
|
||||
import os from 'os';
|
||||
|
||||
const PLIST_LABEL = 'com.happy-cli.daemon';
|
||||
const PLIST_LABEL = 'com.hapi-cli.daemon';
|
||||
const PLIST_FILE = `/Library/LaunchDaemons/${PLIST_LABEL}.plist`;
|
||||
|
||||
// NOTE: Local installation like --local does not make too much sense I feel like
|
||||
@@ -31,7 +31,7 @@ export async function install(): Promise<void> {
|
||||
execSync(`launchctl unload ${PLIST_FILE}`, { stdio: 'inherit' });
|
||||
}
|
||||
|
||||
// Get the path to the happy CLI executable
|
||||
// Get the path to the hapi CLI executable
|
||||
const happyPath = process.argv[0]; // Node.js executable
|
||||
const scriptPath = process.argv[1]; // Script path
|
||||
|
||||
@@ -48,12 +48,12 @@ export async function install(): Promise<void> {
|
||||
<array>
|
||||
<string>${happyPath}</string>
|
||||
<string>${scriptPath}</string>
|
||||
<string>happy-daemon</string>
|
||||
<string>hapi-daemon</string>
|
||||
</array>
|
||||
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>HAPPY_DAEMON_MODE</key>
|
||||
<key>HAPI_DAEMON_MODE</key>
|
||||
<string>true</string>
|
||||
</dict>
|
||||
|
||||
@@ -64,10 +64,10 @@ export async function install(): Promise<void> {
|
||||
<true/>
|
||||
|
||||
<key>StandardErrorPath</key>
|
||||
<string>${os.homedir()}/.happy/daemon.err</string>
|
||||
<string>${os.homedir()}/.hapi/daemon.err</string>
|
||||
|
||||
<key>StandardOutPath</key>
|
||||
<string>${os.homedir()}/.happy/daemon.log</string>
|
||||
<string>${os.homedir()}/.hapi/daemon.log</string>
|
||||
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/tmp</string>
|
||||
@@ -85,10 +85,10 @@ export async function install(): Promise<void> {
|
||||
execSync(`launchctl load ${PLIST_FILE}`, { stdio: 'inherit' });
|
||||
|
||||
logger.info('Daemon installed and started successfully');
|
||||
logger.info('Check logs at ~/.happy/daemon.log');
|
||||
logger.info('Check logs at ~/.hapi/daemon.log');
|
||||
|
||||
} catch (error) {
|
||||
logger.debug('Failed to install daemon:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Uninstallation script for Happy daemon LaunchDaemon
|
||||
* Uninstallation script for HAPI daemon LaunchDaemon
|
||||
*
|
||||
* NOTE: This uninstallation method is currently NOT USED since we moved away from
|
||||
* system-level daemon installation. See install.ts for the full explanation.
|
||||
@@ -12,7 +12,7 @@ import { existsSync, unlinkSync } from 'fs';
|
||||
import { execSync } from 'child_process';
|
||||
import { logger } from '@/ui/logger';
|
||||
|
||||
const PLIST_LABEL = 'com.happy-cli.daemon';
|
||||
const PLIST_LABEL = 'com.hapi-cli.daemon';
|
||||
const PLIST_FILE = `/Library/LaunchDaemons/${PLIST_LABEL}.plist`;
|
||||
|
||||
export async function uninstall(): Promise<void> {
|
||||
@@ -42,4 +42,4 @@ export async function uninstall(): Promise<void> {
|
||||
logger.debug('Failed to uninstall daemon:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ export async function startDaemon(): Promise<void> {
|
||||
//
|
||||
// In case the setup malfunctions - our signal handlers will not properly
|
||||
// shut down. We will force exit the process with code 1.
|
||||
let requestShutdown: (source: 'happy-app' | 'happy-cli' | 'os-signal' | 'exception', errorMessage?: string) => void;
|
||||
let resolvesWhenShutdownRequested = new Promise<({ source: 'happy-app' | 'happy-cli' | 'os-signal' | 'exception', errorMessage?: string })>((resolve) => {
|
||||
let requestShutdown: (source: 'hapi-app' | 'hapi-cli' | 'os-signal' | 'exception', errorMessage?: string) => void;
|
||||
let resolvesWhenShutdownRequested = new Promise<({ source: 'hapi-app' | 'hapi-cli' | 'os-signal' | 'exception', errorMessage?: string })>((resolve) => {
|
||||
requestShutdown = (source, errorMessage) => {
|
||||
logger.debug(`[DAEMON RUN] Requesting shutdown (source: ${source}, errorMessage: ${errorMessage})`);
|
||||
|
||||
@@ -132,7 +132,7 @@ export async function startDaemon(): Promise<void> {
|
||||
// Helper functions
|
||||
const getCurrentChildren = () => Array.from(pidToTrackedSession.values());
|
||||
|
||||
// Handle webhook from happy session reporting itself
|
||||
// Handle webhook from HAPI session reporting itself
|
||||
const onHappySessionWebhook = (sessionId: string, sessionMetadata: Metadata) => {
|
||||
logger.debugLargeJson(`[DAEMON RUN] Session reported`, sessionMetadata);
|
||||
|
||||
@@ -164,7 +164,7 @@ export async function startDaemon(): Promise<void> {
|
||||
} else if (!existingSession) {
|
||||
// New session started externally
|
||||
const trackedSession: TrackedSession = {
|
||||
startedBy: 'happy directly - likely by user from terminal',
|
||||
startedBy: 'hapi directly - likely by user from terminal',
|
||||
happySessionId: sessionId,
|
||||
happySessionMetadataFromLocalWebhook: sessionMetadata,
|
||||
pid
|
||||
@@ -286,7 +286,7 @@ export async function startDaemon(): Promise<void> {
|
||||
logger.debug('[DAEMON RUN] Failed to spawn process - no PID returned');
|
||||
return {
|
||||
type: 'error',
|
||||
errorMessage: 'Failed to spawn Happy process - no PID returned'
|
||||
errorMessage: 'Failed to spawn HAPI process - no PID returned'
|
||||
};
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ export async function startDaemon(): Promise<void> {
|
||||
getChildren: getCurrentChildren,
|
||||
stopSession,
|
||||
spawnSession,
|
||||
requestShutdown: () => requestShutdown('happy-cli'),
|
||||
requestShutdown: () => requestShutdown('hapi-cli'),
|
||||
onHappySessionWebhook
|
||||
});
|
||||
|
||||
@@ -440,7 +440,7 @@ export async function startDaemon(): Promise<void> {
|
||||
apiMachine.setRPCHandlers({
|
||||
spawnSession,
|
||||
stopSession,
|
||||
requestShutdown: () => requestShutdown('happy-app')
|
||||
requestShutdown: () => requestShutdown('hapi-app')
|
||||
});
|
||||
|
||||
// Connect to server
|
||||
@@ -451,7 +451,7 @@ export async function startDaemon(): Promise<void> {
|
||||
// 2. Check if daemon needs update
|
||||
// 3. If outdated, restart with latest version
|
||||
// 4. Write heartbeat
|
||||
const heartbeatIntervalMs = parseInt(process.env.HAPPY_DAEMON_HEARTBEAT_INTERVAL || '60000');
|
||||
const heartbeatIntervalMs = parseInt(process.env.HAPI_DAEMON_HEARTBEAT_INTERVAL || '60000');
|
||||
let heartbeatRunning = false
|
||||
const restartOnStaleVersionAndHeartbeat = setInterval(async () => {
|
||||
if (heartbeatRunning) {
|
||||
@@ -536,7 +536,7 @@ export async function startDaemon(): Promise<void> {
|
||||
}, heartbeatIntervalMs); // Every 60 seconds in production
|
||||
|
||||
// Setup signal handlers
|
||||
const cleanupAndShutdown = async (source: 'happy-app' | 'happy-cli' | 'os-signal' | 'exception', errorMessage?: string) => {
|
||||
const cleanupAndShutdown = async (source: 'hapi-app' | 'hapi-cli' | 'os-signal' | 'exception', errorMessage?: string) => {
|
||||
logger.debug(`[DAEMON RUN] Starting proper cleanup (source: ${source}, errorMessage: ${errorMessage})...`);
|
||||
|
||||
// Clear health check interval
|
||||
|
||||
@@ -10,6 +10,6 @@ export async function uninstall(): Promise<void> {
|
||||
throw new Error('Daemon uninstallation requires sudo privileges. Please run with sudo.');
|
||||
}
|
||||
|
||||
logger.info('Uninstalling Happy CLI daemon for macOS...');
|
||||
logger.info('Uninstalling HAPI CLI daemon for macOS...');
|
||||
await uninstallMac();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user