episoda 0.2.0
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/dist/commands/auth.d.ts +22 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +384 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/dev.d.ts +20 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +305 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/status.d.ts +9 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +75 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/stop.d.ts +17 -0
- package/dist/commands/stop.d.ts.map +1 -0
- package/dist/commands/stop.js +81 -0
- package/dist/commands/stop.js.map +1 -0
- package/dist/core/auth.d.ts +26 -0
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/core/auth.js +113 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/command-protocol.d.ts +262 -0
- package/dist/core/command-protocol.d.ts.map +1 -0
- package/dist/core/command-protocol.js +13 -0
- package/dist/core/command-protocol.js.map +1 -0
- package/dist/core/connection-manager.d.ts +58 -0
- package/dist/core/connection-manager.d.ts.map +1 -0
- package/dist/core/connection-manager.js +215 -0
- package/dist/core/connection-manager.js.map +1 -0
- package/dist/core/errors.d.ts +18 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +55 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/git-executor.d.ts +157 -0
- package/dist/core/git-executor.d.ts.map +1 -0
- package/dist/core/git-executor.js +1605 -0
- package/dist/core/git-executor.js.map +1 -0
- package/dist/core/git-parser.d.ts +40 -0
- package/dist/core/git-parser.d.ts.map +1 -0
- package/dist/core/git-parser.js +194 -0
- package/dist/core/git-parser.js.map +1 -0
- package/dist/core/git-validator.d.ts +42 -0
- package/dist/core/git-validator.d.ts.map +1 -0
- package/dist/core/git-validator.js +102 -0
- package/dist/core/git-validator.js.map +1 -0
- package/dist/core/index.d.ts +17 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +41 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/version.d.ts +9 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core/version.js +19 -0
- package/dist/core/version.js.map +1 -0
- package/dist/core/websocket-client.d.ts +122 -0
- package/dist/core/websocket-client.d.ts.map +1 -0
- package/dist/core/websocket-client.js +438 -0
- package/dist/core/websocket-client.js.map +1 -0
- package/dist/daemon/daemon-manager.d.ts +71 -0
- package/dist/daemon/daemon-manager.d.ts.map +1 -0
- package/dist/daemon/daemon-manager.js +289 -0
- package/dist/daemon/daemon-manager.js.map +1 -0
- package/dist/daemon/daemon-process.d.ts +13 -0
- package/dist/daemon/daemon-process.d.ts.map +1 -0
- package/dist/daemon/daemon-process.js +608 -0
- package/dist/daemon/daemon-process.js.map +1 -0
- package/dist/daemon/machine-id.d.ts +36 -0
- package/dist/daemon/machine-id.d.ts.map +1 -0
- package/dist/daemon/machine-id.js +195 -0
- package/dist/daemon/machine-id.js.map +1 -0
- package/dist/daemon/project-tracker.d.ts +92 -0
- package/dist/daemon/project-tracker.d.ts.map +1 -0
- package/dist/daemon/project-tracker.js +259 -0
- package/dist/daemon/project-tracker.js.map +1 -0
- package/dist/dev-wrapper.d.ts +88 -0
- package/dist/dev-wrapper.d.ts.map +1 -0
- package/dist/dev-wrapper.js +288 -0
- package/dist/dev-wrapper.js.map +1 -0
- package/dist/framework-detector.d.ts +29 -0
- package/dist/framework-detector.d.ts.map +1 -0
- package/dist/framework-detector.js +276 -0
- package/dist/framework-detector.js.map +1 -0
- package/dist/git-helpers/git-credential-helper.d.ts +29 -0
- package/dist/git-helpers/git-credential-helper.d.ts.map +1 -0
- package/dist/git-helpers/git-credential-helper.js +349 -0
- package/dist/git-helpers/git-credential-helper.js.map +1 -0
- package/dist/hooks/post-checkout +296 -0
- package/dist/hooks/pre-commit +139 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +102 -0
- package/dist/index.js.map +1 -0
- package/dist/ipc/ipc-client.d.ts +95 -0
- package/dist/ipc/ipc-client.d.ts.map +1 -0
- package/dist/ipc/ipc-client.js +204 -0
- package/dist/ipc/ipc-client.js.map +1 -0
- package/dist/ipc/ipc-server.d.ts +55 -0
- package/dist/ipc/ipc-server.d.ts.map +1 -0
- package/dist/ipc/ipc-server.js +177 -0
- package/dist/ipc/ipc-server.js.map +1 -0
- package/dist/output.d.ts +48 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +129 -0
- package/dist/output.js.map +1 -0
- package/dist/utils/port-check.d.ts +15 -0
- package/dist/utils/port-check.d.ts.map +1 -0
- package/dist/utils/port-check.js +79 -0
- package/dist/utils/port-check.js.map +1 -0
- package/dist/utils/update-checker.d.ts +23 -0
- package/dist/utils/update-checker.d.ts.map +1 -0
- package/dist/utils/update-checker.js +95 -0
- package/dist/utils/update-checker.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Episoda Daemon Process
|
|
4
|
+
*
|
|
5
|
+
* Main entry point for the persistent daemon that:
|
|
6
|
+
* - Maintains WebSocket connections to multiple projects
|
|
7
|
+
* - Listens for IPC commands from CLI
|
|
8
|
+
* - Handles graceful shutdown
|
|
9
|
+
* - Survives terminal close
|
|
10
|
+
*
|
|
11
|
+
* This file is spawned by daemon-manager.ts in detached mode.
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
const machine_id_1 = require("./machine-id");
|
|
48
|
+
const project_tracker_1 = require("./project-tracker");
|
|
49
|
+
const daemon_manager_1 = require("./daemon-manager");
|
|
50
|
+
const ipc_server_1 = require("../ipc/ipc-server");
|
|
51
|
+
const core_1 = require("../core");
|
|
52
|
+
const update_checker_1 = require("../utils/update-checker");
|
|
53
|
+
const fs = __importStar(require("fs"));
|
|
54
|
+
const os = __importStar(require("os"));
|
|
55
|
+
const path = __importStar(require("path"));
|
|
56
|
+
// EP783: Get current version for update checking
|
|
57
|
+
const packageJson = require('../../package.json');
|
|
58
|
+
/**
|
|
59
|
+
* Daemon state
|
|
60
|
+
*/
|
|
61
|
+
class Daemon {
|
|
62
|
+
constructor() {
|
|
63
|
+
this.machineId = '';
|
|
64
|
+
this.deviceId = null; // EP726: Cached device UUID from server
|
|
65
|
+
this.deviceName = null; // EP661: Cached device name from server
|
|
66
|
+
this.flyMachineId = null; // EP735: Fly.io machine ID for sticky session routing
|
|
67
|
+
// EP738: Removed httpServer - device info now flows through WebSocket broadcast + database
|
|
68
|
+
this.connections = new Map(); // projectPath -> connection
|
|
69
|
+
// EP701: Track which connections are currently live (WebSocket open)
|
|
70
|
+
// Updated by 'auth_success' (add) and 'disconnected' (remove) events
|
|
71
|
+
this.liveConnections = new Set(); // projectPath
|
|
72
|
+
this.shuttingDown = false;
|
|
73
|
+
this.ipcServer = new ipc_server_1.IPCServer();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Start the daemon
|
|
77
|
+
*/
|
|
78
|
+
async start() {
|
|
79
|
+
console.log('[Daemon] Starting Episoda daemon...');
|
|
80
|
+
// Get machine ID
|
|
81
|
+
this.machineId = await (0, machine_id_1.getMachineId)();
|
|
82
|
+
console.log(`[Daemon] Machine ID: ${this.machineId}`);
|
|
83
|
+
// EP726: Load cached device ID from config if available
|
|
84
|
+
const config = await (0, core_1.loadConfig)();
|
|
85
|
+
if (config?.device_id) {
|
|
86
|
+
this.deviceId = config.device_id;
|
|
87
|
+
console.log(`[Daemon] Loaded cached Device ID (UUID): ${this.deviceId}`);
|
|
88
|
+
}
|
|
89
|
+
// Start IPC server
|
|
90
|
+
await this.ipcServer.start();
|
|
91
|
+
console.log('[Daemon] IPC server started');
|
|
92
|
+
// EP738: Removed HTTP server - device info now flows through WebSocket broadcast + database
|
|
93
|
+
// Register IPC command handlers
|
|
94
|
+
this.registerIPCHandlers();
|
|
95
|
+
// Restore connections for tracked projects
|
|
96
|
+
await this.restoreConnections();
|
|
97
|
+
// Setup graceful shutdown
|
|
98
|
+
this.setupShutdownHandlers();
|
|
99
|
+
console.log('[Daemon] Daemon started successfully');
|
|
100
|
+
// EP783: Check for updates in background (non-blocking)
|
|
101
|
+
this.checkAndNotifyUpdates();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* EP783: Check for CLI updates and auto-update in background
|
|
105
|
+
* Non-blocking - runs after daemon starts, fails silently on errors
|
|
106
|
+
*/
|
|
107
|
+
async checkAndNotifyUpdates() {
|
|
108
|
+
try {
|
|
109
|
+
const result = await (0, update_checker_1.checkForUpdates)(packageJson.version);
|
|
110
|
+
if (result.updateAvailable) {
|
|
111
|
+
console.log(`\n⬆️ Update available: ${result.currentVersion} → ${result.latestVersion}`);
|
|
112
|
+
console.log(' Updating in background...\n');
|
|
113
|
+
(0, update_checker_1.performBackgroundUpdate)();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
// Silently ignore - update check is non-critical
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// EP738: Removed startHttpServer - device info now flows through WebSocket broadcast + database
|
|
121
|
+
/**
|
|
122
|
+
* Register IPC command handlers
|
|
123
|
+
*/
|
|
124
|
+
registerIPCHandlers() {
|
|
125
|
+
// Ping - health check
|
|
126
|
+
this.ipcServer.on('ping', async () => {
|
|
127
|
+
return { status: 'ok' };
|
|
128
|
+
});
|
|
129
|
+
// Status - get daemon status
|
|
130
|
+
// EP726: Now includes deviceId (UUID) for unified device identification
|
|
131
|
+
// EP738: Added hostname, platform, arch for status command (HTTP server removed)
|
|
132
|
+
// EP776: Use liveConnections (actual WebSocket state) instead of connections Map
|
|
133
|
+
this.ipcServer.on('status', async () => {
|
|
134
|
+
const projects = (0, project_tracker_1.getAllProjects)().map(p => ({
|
|
135
|
+
id: p.id,
|
|
136
|
+
path: p.path,
|
|
137
|
+
name: p.name,
|
|
138
|
+
connected: this.liveConnections.has(p.path),
|
|
139
|
+
}));
|
|
140
|
+
return {
|
|
141
|
+
running: true,
|
|
142
|
+
machineId: this.machineId,
|
|
143
|
+
deviceId: this.deviceId, // EP726: UUID for unified device identification
|
|
144
|
+
hostname: os.hostname(),
|
|
145
|
+
platform: os.platform(),
|
|
146
|
+
arch: os.arch(),
|
|
147
|
+
projects,
|
|
148
|
+
};
|
|
149
|
+
});
|
|
150
|
+
// EP734: Add project - now blocking, waits for connection to complete
|
|
151
|
+
// This eliminates the need for polling from the client side
|
|
152
|
+
this.ipcServer.on('add-project', async (params) => {
|
|
153
|
+
const { projectId, projectPath } = params;
|
|
154
|
+
(0, project_tracker_1.addProject)(projectId, projectPath);
|
|
155
|
+
try {
|
|
156
|
+
// Await connection - blocks until connected or fails
|
|
157
|
+
await this.connectProject(projectId, projectPath);
|
|
158
|
+
return { success: true, connected: true };
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
162
|
+
return { success: false, connected: false, error: errorMessage };
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
// EP734: Removed connection-status handler - no longer needed with blocking add-project
|
|
166
|
+
// Remove project
|
|
167
|
+
this.ipcServer.on('remove-project', async (params) => {
|
|
168
|
+
const { projectPath } = params;
|
|
169
|
+
await this.disconnectProject(projectPath);
|
|
170
|
+
(0, project_tracker_1.removeProject)(projectPath);
|
|
171
|
+
return { success: true };
|
|
172
|
+
});
|
|
173
|
+
// Connect project
|
|
174
|
+
this.ipcServer.on('connect-project', async (params) => {
|
|
175
|
+
const { projectPath } = params;
|
|
176
|
+
const project = (0, project_tracker_1.getAllProjects)().find(p => p.path === projectPath);
|
|
177
|
+
if (!project) {
|
|
178
|
+
throw new Error('Project not tracked');
|
|
179
|
+
}
|
|
180
|
+
await this.connectProject(project.id, projectPath);
|
|
181
|
+
return { success: true };
|
|
182
|
+
});
|
|
183
|
+
// Disconnect project
|
|
184
|
+
this.ipcServer.on('disconnect-project', async (params) => {
|
|
185
|
+
const { projectPath } = params;
|
|
186
|
+
await this.disconnectProject(projectPath);
|
|
187
|
+
return { success: true };
|
|
188
|
+
});
|
|
189
|
+
// Shutdown
|
|
190
|
+
this.ipcServer.on('shutdown', async () => {
|
|
191
|
+
console.log('[Daemon] Shutdown requested via IPC');
|
|
192
|
+
await this.shutdown();
|
|
193
|
+
return { success: true };
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Restore WebSocket connections for tracked projects
|
|
198
|
+
*/
|
|
199
|
+
async restoreConnections() {
|
|
200
|
+
const projects = (0, project_tracker_1.getAllProjects)();
|
|
201
|
+
for (const project of projects) {
|
|
202
|
+
try {
|
|
203
|
+
await this.connectProject(project.id, project.path);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
console.error(`[Daemon] Failed to restore connection for ${project.name}:`, error);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Connect to a project's WebSocket
|
|
212
|
+
*/
|
|
213
|
+
async connectProject(projectId, projectPath) {
|
|
214
|
+
// Skip if already connected
|
|
215
|
+
if (this.connections.has(projectPath)) {
|
|
216
|
+
console.log(`[Daemon] Already connected to ${projectPath}`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// Load auth token from config
|
|
220
|
+
const config = await (0, core_1.loadConfig)();
|
|
221
|
+
if (!config || !config.access_token) {
|
|
222
|
+
throw new Error('No access token found. Please run: episoda auth');
|
|
223
|
+
}
|
|
224
|
+
// EP734: Removed pre-flight health check - WebSocket will fail naturally if server is down
|
|
225
|
+
// This saves ~200-500ms on every connection attempt
|
|
226
|
+
// EP734: Determine server URL using cached settings (avoids network call)
|
|
227
|
+
// Priority: 1. Cached local_server_url, 2. Global config api_url, 3. Default production
|
|
228
|
+
let serverUrl = config.api_url || process.env.EPISODA_API_URL || 'https://episoda.dev';
|
|
229
|
+
// Use cached local_server_url if available
|
|
230
|
+
if (config.project_settings?.local_server_url) {
|
|
231
|
+
serverUrl = config.project_settings.local_server_url;
|
|
232
|
+
console.log(`[Daemon] Using cached server URL: ${serverUrl}`);
|
|
233
|
+
}
|
|
234
|
+
// EP593: Connect to WebSocket server on port 3001 (standalone WebSocket server)
|
|
235
|
+
const serverUrlObj = new URL(serverUrl);
|
|
236
|
+
const wsProtocol = serverUrlObj.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
237
|
+
const wsPort = process.env.EPISODA_WS_PORT || '3001';
|
|
238
|
+
const wsUrl = `${wsProtocol}//${serverUrlObj.hostname}:${wsPort}`;
|
|
239
|
+
console.log(`[Daemon] Connecting to ${wsUrl} for project ${projectId}...`);
|
|
240
|
+
// Create EpisodaClient (handles auth, reconnection, heartbeat)
|
|
241
|
+
const client = new core_1.EpisodaClient();
|
|
242
|
+
// Create GitExecutor for this project
|
|
243
|
+
const gitExecutor = new core_1.GitExecutor();
|
|
244
|
+
// Store connection
|
|
245
|
+
const connection = {
|
|
246
|
+
projectId,
|
|
247
|
+
projectPath,
|
|
248
|
+
client,
|
|
249
|
+
gitExecutor,
|
|
250
|
+
};
|
|
251
|
+
this.connections.set(projectPath, connection);
|
|
252
|
+
// Register command handler
|
|
253
|
+
client.on('command', async (message) => {
|
|
254
|
+
if (message.type === 'command' && message.command) {
|
|
255
|
+
console.log(`[Daemon] Received command for ${projectId}:`, message.command);
|
|
256
|
+
// EP605: Update activity timestamp to reset idle detection
|
|
257
|
+
client.updateActivity();
|
|
258
|
+
try {
|
|
259
|
+
// Execute git command with working directory
|
|
260
|
+
const result = await gitExecutor.execute(message.command, {
|
|
261
|
+
cwd: projectPath
|
|
262
|
+
});
|
|
263
|
+
// Send result back
|
|
264
|
+
await client.send({
|
|
265
|
+
type: 'result',
|
|
266
|
+
commandId: message.id,
|
|
267
|
+
result
|
|
268
|
+
});
|
|
269
|
+
console.log(`[Daemon] Command completed for ${projectId}:`, result.success ? 'success' : 'failed');
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
// Send error result
|
|
273
|
+
await client.send({
|
|
274
|
+
type: 'result',
|
|
275
|
+
commandId: message.id,
|
|
276
|
+
result: {
|
|
277
|
+
success: false,
|
|
278
|
+
error: 'UNKNOWN_ERROR',
|
|
279
|
+
output: error instanceof Error ? error.message : String(error)
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
console.error(`[Daemon] Command execution error for ${projectId}:`, error);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
// Register shutdown handler - allows server to request graceful shutdown
|
|
287
|
+
// EP613: Only exit on user-requested shutdowns, reconnect for server restarts
|
|
288
|
+
client.on('shutdown', async (message) => {
|
|
289
|
+
const shutdownMessage = message;
|
|
290
|
+
const reason = shutdownMessage.reason || 'unknown';
|
|
291
|
+
console.log(`[Daemon] Received shutdown request from server for ${projectId}`);
|
|
292
|
+
console.log(`[Daemon] Reason: ${reason} - ${shutdownMessage.message || 'No message'}`);
|
|
293
|
+
if (reason === 'user_requested') {
|
|
294
|
+
// User explicitly requested disconnect - exit cleanly
|
|
295
|
+
console.log(`[Daemon] User requested disconnect, shutting down...`);
|
|
296
|
+
await this.cleanupAndExit();
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
// Server restart or deployment - don't exit, let WebSocket reconnection handle it
|
|
300
|
+
console.log(`[Daemon] Server shutdown (${reason}), will reconnect automatically...`);
|
|
301
|
+
// The WebSocket close event will trigger reconnection via EpisodaClient
|
|
302
|
+
// We don't call process.exit() here - just let the connection close naturally
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
// Register auth success handler
|
|
306
|
+
client.on('auth_success', async (message) => {
|
|
307
|
+
console.log(`[Daemon] Authenticated for project ${projectId}`);
|
|
308
|
+
(0, project_tracker_1.touchProject)(projectPath);
|
|
309
|
+
// EP701: Mark connection as live (for /device-info endpoint)
|
|
310
|
+
this.liveConnections.add(projectPath);
|
|
311
|
+
// EP595: Configure git with userId and workspaceId for post-checkout hook
|
|
312
|
+
// EP655: Also configure machineId for device isolation
|
|
313
|
+
// EP661: Cache deviceName for browser identification
|
|
314
|
+
// EP726: Cache deviceId (UUID) for unified device identification
|
|
315
|
+
// EP735: Cache flyMachineId for sticky session routing
|
|
316
|
+
const authMessage = message;
|
|
317
|
+
if (authMessage.userId && authMessage.workspaceId) {
|
|
318
|
+
// EP726: Pass deviceId to configureGitUser so it's stored in git config
|
|
319
|
+
await this.configureGitUser(projectPath, authMessage.userId, authMessage.workspaceId, this.machineId, projectId, authMessage.deviceId);
|
|
320
|
+
// EP610: Install git hooks after configuring git user
|
|
321
|
+
await this.installGitHooks(projectPath);
|
|
322
|
+
}
|
|
323
|
+
// EP661: Store device name for logging and config
|
|
324
|
+
if (authMessage.deviceName) {
|
|
325
|
+
this.deviceName = authMessage.deviceName;
|
|
326
|
+
console.log(`[Daemon] Device name: ${this.deviceName}`);
|
|
327
|
+
}
|
|
328
|
+
// EP726: Cache device UUID for unified device identification
|
|
329
|
+
// Persist to config for future use
|
|
330
|
+
if (authMessage.deviceId) {
|
|
331
|
+
this.deviceId = authMessage.deviceId;
|
|
332
|
+
console.log(`[Daemon] Device ID (UUID): ${this.deviceId}`);
|
|
333
|
+
// Persist deviceId to config file so it's available on daemon restart
|
|
334
|
+
await this.cacheDeviceId(authMessage.deviceId);
|
|
335
|
+
}
|
|
336
|
+
// EP735: Cache Fly.io machine ID for sticky session routing
|
|
337
|
+
// Only set when server is running on Fly.io, null otherwise
|
|
338
|
+
if (authMessage.flyMachineId) {
|
|
339
|
+
this.flyMachineId = authMessage.flyMachineId;
|
|
340
|
+
console.log(`[Daemon] Fly Machine ID: ${this.flyMachineId}`);
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
// Register error handler
|
|
344
|
+
client.on('error', (message) => {
|
|
345
|
+
console.error(`[Daemon] Server error for ${projectId}:`, message);
|
|
346
|
+
});
|
|
347
|
+
// EP701: Register disconnected handler to track connection state
|
|
348
|
+
// Removes from liveConnections immediately so /device-info returns accurate state
|
|
349
|
+
// Keeps entry in connections map for potential reconnection (client handles reconnect internally)
|
|
350
|
+
client.on('disconnected', (event) => {
|
|
351
|
+
const disconnectEvent = event;
|
|
352
|
+
console.log(`[Daemon] Connection closed for ${projectId}: code=${disconnectEvent.code}, willReconnect=${disconnectEvent.willReconnect}`);
|
|
353
|
+
// Always remove from liveConnections - connection is dead until reconnected
|
|
354
|
+
this.liveConnections.delete(projectPath);
|
|
355
|
+
// Only remove from connections map if we won't reconnect (intentional disconnect)
|
|
356
|
+
if (!disconnectEvent.willReconnect) {
|
|
357
|
+
this.connections.delete(projectPath);
|
|
358
|
+
console.log(`[Daemon] Removed connection for ${projectPath} from map`);
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
try {
|
|
362
|
+
// EP601: Read daemon PID from file
|
|
363
|
+
let daemonPid;
|
|
364
|
+
try {
|
|
365
|
+
const pidPath = (0, daemon_manager_1.getPidFilePath)();
|
|
366
|
+
if (fs.existsSync(pidPath)) {
|
|
367
|
+
const pidStr = fs.readFileSync(pidPath, 'utf-8').trim();
|
|
368
|
+
daemonPid = parseInt(pidStr, 10);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
catch (pidError) {
|
|
372
|
+
console.warn(`[Daemon] Could not read daemon PID:`, pidError instanceof Error ? pidError.message : pidError);
|
|
373
|
+
}
|
|
374
|
+
// Connect with OAuth token, machine ID, and device info (EP596, EP601: includes daemonPid)
|
|
375
|
+
await client.connect(wsUrl, config.access_token, this.machineId, {
|
|
376
|
+
hostname: os.hostname(),
|
|
377
|
+
osPlatform: os.platform(),
|
|
378
|
+
osArch: os.arch(),
|
|
379
|
+
daemonPid
|
|
380
|
+
});
|
|
381
|
+
console.log(`[Daemon] Successfully connected to project ${projectId}`);
|
|
382
|
+
}
|
|
383
|
+
catch (error) {
|
|
384
|
+
console.error(`[Daemon] Failed to connect to ${projectId}:`, error);
|
|
385
|
+
this.connections.delete(projectPath);
|
|
386
|
+
throw error;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Disconnect from a project's WebSocket
|
|
391
|
+
*/
|
|
392
|
+
async disconnectProject(projectPath) {
|
|
393
|
+
const connection = this.connections.get(projectPath);
|
|
394
|
+
if (!connection) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
// Clear reconnect timer
|
|
398
|
+
if (connection.reconnectTimer) {
|
|
399
|
+
clearTimeout(connection.reconnectTimer);
|
|
400
|
+
}
|
|
401
|
+
// Disconnect client (handles WebSocket close gracefully)
|
|
402
|
+
await connection.client.disconnect();
|
|
403
|
+
this.connections.delete(projectPath);
|
|
404
|
+
this.liveConnections.delete(projectPath); // EP701: Also clean up liveConnections
|
|
405
|
+
console.log(`[Daemon] Disconnected from ${projectPath}`);
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Setup graceful shutdown handlers
|
|
409
|
+
* EP613: Now uses cleanupAndExit to ensure PID file is removed
|
|
410
|
+
*/
|
|
411
|
+
setupShutdownHandlers() {
|
|
412
|
+
const shutdownHandler = async (signal) => {
|
|
413
|
+
console.log(`[Daemon] Received ${signal}, shutting down...`);
|
|
414
|
+
await this.cleanupAndExit();
|
|
415
|
+
};
|
|
416
|
+
process.on('SIGTERM', () => shutdownHandler('SIGTERM'));
|
|
417
|
+
process.on('SIGINT', () => shutdownHandler('SIGINT'));
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* EP595: Configure git with user and workspace ID for post-checkout hook
|
|
421
|
+
* EP655: Added machineId for device isolation in multi-device environments
|
|
422
|
+
* EP725: Added projectId for main branch badge tracking
|
|
423
|
+
* EP726: Added deviceId (UUID) for unified device identification
|
|
424
|
+
*
|
|
425
|
+
* This stores the IDs in .git/config so the post-checkout hook can
|
|
426
|
+
* update module.checkout_* fields when git operations happen from terminal.
|
|
427
|
+
*/
|
|
428
|
+
async configureGitUser(projectPath, userId, workspaceId, machineId, projectId, deviceId) {
|
|
429
|
+
try {
|
|
430
|
+
const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
431
|
+
// Set git config values in the project's .git/config
|
|
432
|
+
execSync(`git config episoda.userId ${userId}`, {
|
|
433
|
+
cwd: projectPath,
|
|
434
|
+
encoding: 'utf8',
|
|
435
|
+
stdio: 'pipe'
|
|
436
|
+
});
|
|
437
|
+
execSync(`git config episoda.workspaceId ${workspaceId}`, {
|
|
438
|
+
cwd: projectPath,
|
|
439
|
+
encoding: 'utf8',
|
|
440
|
+
stdio: 'pipe'
|
|
441
|
+
});
|
|
442
|
+
// EP655: Set machineId for device isolation in post-checkout hook
|
|
443
|
+
execSync(`git config episoda.machineId ${machineId}`, {
|
|
444
|
+
cwd: projectPath,
|
|
445
|
+
encoding: 'utf8',
|
|
446
|
+
stdio: 'pipe'
|
|
447
|
+
});
|
|
448
|
+
// EP725: Set projectId for main branch badge tracking
|
|
449
|
+
// This ensures main branch checkouts are recorded with project_id
|
|
450
|
+
execSync(`git config episoda.projectId ${projectId}`, {
|
|
451
|
+
cwd: projectPath,
|
|
452
|
+
encoding: 'utf8',
|
|
453
|
+
stdio: 'pipe'
|
|
454
|
+
});
|
|
455
|
+
// EP726: Set deviceId (UUID) for unified device identification
|
|
456
|
+
// This allows the post-checkout hook to pass the UUID to the database
|
|
457
|
+
if (deviceId) {
|
|
458
|
+
execSync(`git config episoda.deviceId ${deviceId}`, {
|
|
459
|
+
cwd: projectPath,
|
|
460
|
+
encoding: 'utf8',
|
|
461
|
+
stdio: 'pipe'
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
console.log(`[Daemon] Configured git for project: episoda.userId=${userId}, machineId=${machineId}, projectId=${projectId}${deviceId ? `, deviceId=${deviceId}` : ''}`);
|
|
465
|
+
}
|
|
466
|
+
catch (error) {
|
|
467
|
+
// Non-fatal error - git hook just won't work
|
|
468
|
+
console.warn(`[Daemon] Failed to configure git user for ${projectPath}:`, error instanceof Error ? error.message : error);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* EP610: Install git hooks from bundled files
|
|
473
|
+
*
|
|
474
|
+
* Installs post-checkout and pre-commit hooks to enable:
|
|
475
|
+
* - Branch tracking (post-checkout updates module.checkout_* fields)
|
|
476
|
+
* - Main branch protection (pre-commit blocks direct commits to main)
|
|
477
|
+
*/
|
|
478
|
+
async installGitHooks(projectPath) {
|
|
479
|
+
const hooks = ['post-checkout', 'pre-commit'];
|
|
480
|
+
const hooksDir = path.join(projectPath, '.git', 'hooks');
|
|
481
|
+
// Ensure hooks directory exists
|
|
482
|
+
if (!fs.existsSync(hooksDir)) {
|
|
483
|
+
console.warn(`[Daemon] Hooks directory not found: ${hooksDir}`);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
for (const hookName of hooks) {
|
|
487
|
+
try {
|
|
488
|
+
const hookPath = path.join(hooksDir, hookName);
|
|
489
|
+
// Read bundled hook content
|
|
490
|
+
// __dirname in compiled code points to dist/daemon/, hooks are in dist/hooks/
|
|
491
|
+
const bundledHookPath = path.join(__dirname, '..', 'hooks', hookName);
|
|
492
|
+
if (!fs.existsSync(bundledHookPath)) {
|
|
493
|
+
console.warn(`[Daemon] Bundled hook not found: ${bundledHookPath}`);
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
const hookContent = fs.readFileSync(bundledHookPath, 'utf-8');
|
|
497
|
+
// Check if hook already exists with same content
|
|
498
|
+
if (fs.existsSync(hookPath)) {
|
|
499
|
+
const existingContent = fs.readFileSync(hookPath, 'utf-8');
|
|
500
|
+
if (existingContent === hookContent) {
|
|
501
|
+
// Hook is up to date
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
// Write hook file
|
|
506
|
+
fs.writeFileSync(hookPath, hookContent, { mode: 0o755 });
|
|
507
|
+
console.log(`[Daemon] Installed git hook: ${hookName}`);
|
|
508
|
+
}
|
|
509
|
+
catch (error) {
|
|
510
|
+
// Non-fatal - just log warning
|
|
511
|
+
console.warn(`[Daemon] Failed to install ${hookName} hook:`, error instanceof Error ? error.message : error);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* EP726: Cache device UUID to config file
|
|
517
|
+
*
|
|
518
|
+
* Persists the device_id (UUID) received from the server so it's available
|
|
519
|
+
* on daemon restart without needing to re-register the device.
|
|
520
|
+
*/
|
|
521
|
+
async cacheDeviceId(deviceId) {
|
|
522
|
+
try {
|
|
523
|
+
const config = await (0, core_1.loadConfig)();
|
|
524
|
+
if (!config) {
|
|
525
|
+
console.warn('[Daemon] Cannot cache device ID - no config found');
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
// Only update if device_id has changed
|
|
529
|
+
if (config.device_id === deviceId) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
// Update config with device_id and machine_id
|
|
533
|
+
const updatedConfig = {
|
|
534
|
+
...config,
|
|
535
|
+
device_id: deviceId,
|
|
536
|
+
machine_id: this.machineId
|
|
537
|
+
};
|
|
538
|
+
await (0, core_1.saveConfig)(updatedConfig);
|
|
539
|
+
console.log(`[Daemon] Cached device ID to config: ${deviceId}`);
|
|
540
|
+
}
|
|
541
|
+
catch (error) {
|
|
542
|
+
console.warn('[Daemon] Failed to cache device ID:', error instanceof Error ? error.message : error);
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Gracefully shutdown daemon
|
|
547
|
+
*/
|
|
548
|
+
async shutdown() {
|
|
549
|
+
if (this.shuttingDown)
|
|
550
|
+
return;
|
|
551
|
+
this.shuttingDown = true;
|
|
552
|
+
console.log('[Daemon] Shutting down...');
|
|
553
|
+
// Close all WebSocket connections
|
|
554
|
+
for (const [projectPath, connection] of this.connections) {
|
|
555
|
+
if (connection.reconnectTimer) {
|
|
556
|
+
clearTimeout(connection.reconnectTimer);
|
|
557
|
+
}
|
|
558
|
+
await connection.client.disconnect();
|
|
559
|
+
}
|
|
560
|
+
this.connections.clear();
|
|
561
|
+
// EP738: Removed HTTP server cleanup - server no longer exists
|
|
562
|
+
// Stop IPC server
|
|
563
|
+
await this.ipcServer.stop();
|
|
564
|
+
console.log('[Daemon] Shutdown complete');
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* EP613: Clean up PID file and exit gracefully
|
|
568
|
+
* Called when user explicitly requests disconnect
|
|
569
|
+
*/
|
|
570
|
+
async cleanupAndExit() {
|
|
571
|
+
await this.shutdown();
|
|
572
|
+
// Clean up PID file
|
|
573
|
+
try {
|
|
574
|
+
const pidPath = (0, daemon_manager_1.getPidFilePath)();
|
|
575
|
+
if (fs.existsSync(pidPath)) {
|
|
576
|
+
fs.unlinkSync(pidPath);
|
|
577
|
+
console.log('[Daemon] PID file cleaned up');
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
catch (error) {
|
|
581
|
+
console.error('[Daemon] Failed to clean up PID file:', error);
|
|
582
|
+
}
|
|
583
|
+
console.log('[Daemon] Exiting...');
|
|
584
|
+
process.exit(0);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Main entry point
|
|
589
|
+
*/
|
|
590
|
+
async function main() {
|
|
591
|
+
// Only run if explicitly in daemon mode
|
|
592
|
+
if (!process.env.EPISODA_DAEMON_MODE) {
|
|
593
|
+
console.error('This script should only be run by daemon-manager');
|
|
594
|
+
process.exit(1);
|
|
595
|
+
}
|
|
596
|
+
const daemon = new Daemon();
|
|
597
|
+
await daemon.start();
|
|
598
|
+
// Keep process alive
|
|
599
|
+
await new Promise(() => {
|
|
600
|
+
// Never resolves - daemon runs until killed
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
// Run daemon
|
|
604
|
+
main().catch(error => {
|
|
605
|
+
console.error('[Daemon] Fatal error:', error);
|
|
606
|
+
process.exit(1);
|
|
607
|
+
});
|
|
608
|
+
//# sourceMappingURL=daemon-process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-process.js","sourceRoot":"","sources":["../../src/daemon/daemon-process.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Machine ID generation and management
|
|
3
|
+
*
|
|
4
|
+
* Generates a stable machine identifier used for multi-machine connection tracking.
|
|
5
|
+
* Format: {hostname}-{hardware-uuid-prefix}
|
|
6
|
+
* Example: "Alans-MacBook-Pro-a3f2b1c4"
|
|
7
|
+
*
|
|
8
|
+
* EP731: Uses hardware UUID instead of random UUID to prevent duplicate device
|
|
9
|
+
* registrations when ~/.episoda syncs between devices via iCloud/Dropbox.
|
|
10
|
+
*
|
|
11
|
+
* Properties:
|
|
12
|
+
* - Stable across daemon restarts
|
|
13
|
+
* - Unique per PHYSICAL machine (uses hardware UUID)
|
|
14
|
+
* - Human-readable (includes hostname)
|
|
15
|
+
* - Survives OS reboots
|
|
16
|
+
* - Cannot sync between devices (hardware-based)
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Get or generate machine ID
|
|
20
|
+
*
|
|
21
|
+
* Reads from config directory's machine-id if exists, otherwise generates new one
|
|
22
|
+
* and saves it for future use.
|
|
23
|
+
*
|
|
24
|
+
* @returns Machine ID string
|
|
25
|
+
*/
|
|
26
|
+
export declare function getMachineId(): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Reset machine ID (force regeneration)
|
|
29
|
+
*
|
|
30
|
+
* Deletes the stored machine ID file, forcing a new ID to be generated
|
|
31
|
+
* on next getMachineId() call.
|
|
32
|
+
*
|
|
33
|
+
* Use case: Developer explicitly wants to change their machine identity
|
|
34
|
+
*/
|
|
35
|
+
export declare function resetMachineId(): void;
|
|
36
|
+
//# sourceMappingURL=machine-id.d.ts.map
|