episoda 0.2.11 → 0.2.12
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/daemon/daemon-process.js +39 -122
- package/dist/daemon/daemon-process.js.map +1 -1
- package/dist/index.js +42 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -2068,11 +2068,11 @@ var require_auth = __commonJS({
|
|
|
2068
2068
|
exports2.validateToken = validateToken;
|
|
2069
2069
|
var fs6 = __importStar(require("fs"));
|
|
2070
2070
|
var path7 = __importStar(require("path"));
|
|
2071
|
-
var
|
|
2071
|
+
var os2 = __importStar(require("os"));
|
|
2072
2072
|
var child_process_1 = require("child_process");
|
|
2073
2073
|
var DEFAULT_CONFIG_FILE = "config.json";
|
|
2074
2074
|
function getConfigDir5() {
|
|
2075
|
-
return process.env.EPISODA_CONFIG_DIR || path7.join(
|
|
2075
|
+
return process.env.EPISODA_CONFIG_DIR || path7.join(os2.homedir(), ".episoda");
|
|
2076
2076
|
}
|
|
2077
2077
|
function getConfigPath(configPath) {
|
|
2078
2078
|
if (configPath) {
|
|
@@ -2228,7 +2228,7 @@ var require_package = __commonJS({
|
|
|
2228
2228
|
"package.json"(exports2, module2) {
|
|
2229
2229
|
module2.exports = {
|
|
2230
2230
|
name: "episoda",
|
|
2231
|
-
version: "0.2.
|
|
2231
|
+
version: "0.2.11",
|
|
2232
2232
|
description: "CLI tool for Episoda local development workflow orchestration",
|
|
2233
2233
|
main: "dist/index.js",
|
|
2234
2234
|
types: "dist/index.d.ts",
|
|
@@ -2283,19 +2283,29 @@ var require_package = __commonJS({
|
|
|
2283
2283
|
});
|
|
2284
2284
|
|
|
2285
2285
|
// src/daemon/machine-id.ts
|
|
2286
|
-
var os = __toESM(require("os"));
|
|
2287
2286
|
var fs = __toESM(require("fs"));
|
|
2288
2287
|
var path = __toESM(require("path"));
|
|
2289
2288
|
var crypto = __toESM(require("crypto"));
|
|
2290
2289
|
var import_child_process = require("child_process");
|
|
2291
2290
|
var import_core = __toESM(require_dist());
|
|
2291
|
+
function isValidUUID(str) {
|
|
2292
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
2293
|
+
return uuidRegex.test(str);
|
|
2294
|
+
}
|
|
2292
2295
|
async function getMachineId() {
|
|
2293
2296
|
const machineIdPath = path.join((0, import_core.getConfigDir)(), "machine-id");
|
|
2294
2297
|
try {
|
|
2295
2298
|
if (fs.existsSync(machineIdPath)) {
|
|
2296
|
-
const
|
|
2297
|
-
if (
|
|
2298
|
-
|
|
2299
|
+
const existingId = fs.readFileSync(machineIdPath, "utf-8").trim();
|
|
2300
|
+
if (existingId) {
|
|
2301
|
+
if (isValidUUID(existingId)) {
|
|
2302
|
+
return existingId;
|
|
2303
|
+
}
|
|
2304
|
+
console.log("[MachineId] Migrating legacy machine ID to UUID format...");
|
|
2305
|
+
const newUUID = generateMachineId();
|
|
2306
|
+
fs.writeFileSync(machineIdPath, newUUID, "utf-8");
|
|
2307
|
+
console.log(`[MachineId] Migrated: ${existingId} \u2192 ${newUUID}`);
|
|
2308
|
+
return newUUID;
|
|
2299
2309
|
}
|
|
2300
2310
|
}
|
|
2301
2311
|
} catch (error) {
|
|
@@ -2354,10 +2364,21 @@ function getHardwareUUID() {
|
|
|
2354
2364
|
return crypto.randomUUID();
|
|
2355
2365
|
}
|
|
2356
2366
|
function generateMachineId() {
|
|
2357
|
-
const hostname4 = os.hostname();
|
|
2358
2367
|
const hwUUID = getHardwareUUID();
|
|
2359
|
-
|
|
2360
|
-
|
|
2368
|
+
if (isValidUUID(hwUUID)) {
|
|
2369
|
+
return hwUUID.toLowerCase();
|
|
2370
|
+
}
|
|
2371
|
+
const hash = crypto.createHash("sha256").update(hwUUID).digest("hex");
|
|
2372
|
+
const uuid = [
|
|
2373
|
+
hash.slice(0, 8),
|
|
2374
|
+
hash.slice(8, 12),
|
|
2375
|
+
"4" + hash.slice(13, 16),
|
|
2376
|
+
// Version 4
|
|
2377
|
+
(parseInt(hash.slice(16, 17), 16) & 3 | 8).toString(16) + hash.slice(17, 20),
|
|
2378
|
+
// Variant
|
|
2379
|
+
hash.slice(20, 32)
|
|
2380
|
+
].join("-");
|
|
2381
|
+
return uuid.toLowerCase();
|
|
2361
2382
|
}
|
|
2362
2383
|
|
|
2363
2384
|
// src/daemon/project-tracker.ts
|
|
@@ -2615,97 +2636,6 @@ function performBackgroundUpdate() {
|
|
|
2615
2636
|
}
|
|
2616
2637
|
}
|
|
2617
2638
|
|
|
2618
|
-
// src/daemon/identity-server.ts
|
|
2619
|
-
var http = __toESM(require("http"));
|
|
2620
|
-
var os2 = __toESM(require("os"));
|
|
2621
|
-
var IDENTITY_SERVER_PORT = 3002;
|
|
2622
|
-
var IdentityServer = class {
|
|
2623
|
-
constructor(machineId) {
|
|
2624
|
-
this.server = null;
|
|
2625
|
-
this.isConnected = false;
|
|
2626
|
-
this.machineId = machineId;
|
|
2627
|
-
}
|
|
2628
|
-
/**
|
|
2629
|
-
* Update connection status
|
|
2630
|
-
* Called when WebSocket connection state changes
|
|
2631
|
-
*/
|
|
2632
|
-
setConnected(connected) {
|
|
2633
|
-
this.isConnected = connected;
|
|
2634
|
-
}
|
|
2635
|
-
/**
|
|
2636
|
-
* Start the identity server on localhost:3002
|
|
2637
|
-
*/
|
|
2638
|
-
async start() {
|
|
2639
|
-
return new Promise((resolve2, reject) => {
|
|
2640
|
-
this.server = http.createServer((req, res) => {
|
|
2641
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
2642
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
2643
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
2644
|
-
res.setHeader("Access-Control-Allow-Private-Network", "true");
|
|
2645
|
-
if (req.method === "OPTIONS") {
|
|
2646
|
-
res.writeHead(204);
|
|
2647
|
-
res.end();
|
|
2648
|
-
return;
|
|
2649
|
-
}
|
|
2650
|
-
if (req.method !== "GET") {
|
|
2651
|
-
res.writeHead(405, { "Content-Type": "application/json" });
|
|
2652
|
-
res.end(JSON.stringify({ error: "Method not allowed" }));
|
|
2653
|
-
return;
|
|
2654
|
-
}
|
|
2655
|
-
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
2656
|
-
if (url.pathname === "/identity") {
|
|
2657
|
-
const response = {
|
|
2658
|
-
machineId: this.machineId,
|
|
2659
|
-
hostname: os2.hostname(),
|
|
2660
|
-
platform: os2.platform(),
|
|
2661
|
-
arch: os2.arch(),
|
|
2662
|
-
connected: this.isConnected
|
|
2663
|
-
};
|
|
2664
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2665
|
-
res.end(JSON.stringify(response));
|
|
2666
|
-
return;
|
|
2667
|
-
}
|
|
2668
|
-
if (url.pathname === "/health") {
|
|
2669
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2670
|
-
res.end(JSON.stringify({ status: "ok", machineId: this.machineId }));
|
|
2671
|
-
return;
|
|
2672
|
-
}
|
|
2673
|
-
res.writeHead(404, { "Content-Type": "application/json" });
|
|
2674
|
-
res.end(JSON.stringify({ error: "Not found" }));
|
|
2675
|
-
});
|
|
2676
|
-
this.server.listen(IDENTITY_SERVER_PORT, "127.0.0.1", () => {
|
|
2677
|
-
console.log(`[IdentityServer] Started on http://127.0.0.1:${IDENTITY_SERVER_PORT}`);
|
|
2678
|
-
resolve2();
|
|
2679
|
-
});
|
|
2680
|
-
this.server.on("error", (err) => {
|
|
2681
|
-
if (err.code === "EADDRINUSE") {
|
|
2682
|
-
console.warn(`[IdentityServer] Port ${IDENTITY_SERVER_PORT} already in use, skipping`);
|
|
2683
|
-
resolve2();
|
|
2684
|
-
} else {
|
|
2685
|
-
console.error("[IdentityServer] Failed to start:", err.message);
|
|
2686
|
-
reject(err);
|
|
2687
|
-
}
|
|
2688
|
-
});
|
|
2689
|
-
});
|
|
2690
|
-
}
|
|
2691
|
-
/**
|
|
2692
|
-
* Stop the identity server
|
|
2693
|
-
*/
|
|
2694
|
-
async stop() {
|
|
2695
|
-
return new Promise((resolve2) => {
|
|
2696
|
-
if (this.server) {
|
|
2697
|
-
this.server.close(() => {
|
|
2698
|
-
console.log("[IdentityServer] Stopped");
|
|
2699
|
-
this.server = null;
|
|
2700
|
-
resolve2();
|
|
2701
|
-
});
|
|
2702
|
-
} else {
|
|
2703
|
-
resolve2();
|
|
2704
|
-
}
|
|
2705
|
-
});
|
|
2706
|
-
}
|
|
2707
|
-
};
|
|
2708
|
-
|
|
2709
2639
|
// src/daemon/handlers/file-handlers.ts
|
|
2710
2640
|
var fs4 = __toESM(require("fs"));
|
|
2711
2641
|
var path5 = __toESM(require("path"));
|
|
@@ -3172,7 +3102,7 @@ async function handleExec(command, projectPath) {
|
|
|
3172
3102
|
|
|
3173
3103
|
// src/daemon/daemon-process.ts
|
|
3174
3104
|
var fs5 = __toESM(require("fs"));
|
|
3175
|
-
var
|
|
3105
|
+
var os = __toESM(require("os"));
|
|
3176
3106
|
var path6 = __toESM(require("path"));
|
|
3177
3107
|
var packageJson = require_package();
|
|
3178
3108
|
var Daemon = class {
|
|
@@ -3183,8 +3113,7 @@ var Daemon = class {
|
|
|
3183
3113
|
this.deviceName = null;
|
|
3184
3114
|
// EP661: Cached device name from server
|
|
3185
3115
|
this.flyMachineId = null;
|
|
3186
|
-
|
|
3187
|
-
// EP803: Local identity server for browser detection
|
|
3116
|
+
// EP812: Removed identityServer - browser identity now uses cookie-based pairing
|
|
3188
3117
|
this.connections = /* @__PURE__ */ new Map();
|
|
3189
3118
|
// projectPath -> connection
|
|
3190
3119
|
// EP701: Track which connections are currently live (WebSocket open)
|
|
@@ -3208,8 +3137,6 @@ var Daemon = class {
|
|
|
3208
3137
|
}
|
|
3209
3138
|
await this.ipcServer.start();
|
|
3210
3139
|
console.log("[Daemon] IPC server started");
|
|
3211
|
-
this.identityServer = new IdentityServer(this.machineId);
|
|
3212
|
-
await this.identityServer.start();
|
|
3213
3140
|
this.registerIPCHandlers();
|
|
3214
3141
|
await this.restoreConnections();
|
|
3215
3142
|
this.setupShutdownHandlers();
|
|
@@ -3252,9 +3179,9 @@ var Daemon = class {
|
|
|
3252
3179
|
machineId: this.machineId,
|
|
3253
3180
|
deviceId: this.deviceId,
|
|
3254
3181
|
// EP726: UUID for unified device identification
|
|
3255
|
-
hostname:
|
|
3256
|
-
platform:
|
|
3257
|
-
arch:
|
|
3182
|
+
hostname: os.hostname(),
|
|
3183
|
+
platform: os.platform(),
|
|
3184
|
+
arch: os.arch(),
|
|
3258
3185
|
projects
|
|
3259
3186
|
};
|
|
3260
3187
|
});
|
|
@@ -3468,9 +3395,6 @@ var Daemon = class {
|
|
|
3468
3395
|
console.log(`[Daemon] Authenticated for project ${projectId}`);
|
|
3469
3396
|
touchProject(projectPath);
|
|
3470
3397
|
this.liveConnections.add(projectPath);
|
|
3471
|
-
if (this.identityServer) {
|
|
3472
|
-
this.identityServer.setConnected(true);
|
|
3473
|
-
}
|
|
3474
3398
|
const authMessage = message;
|
|
3475
3399
|
if (authMessage.userId && authMessage.workspaceId) {
|
|
3476
3400
|
await this.configureGitUser(projectPath, authMessage.userId, authMessage.workspaceId, this.machineId, projectId, authMessage.deviceId);
|
|
@@ -3497,9 +3421,6 @@ var Daemon = class {
|
|
|
3497
3421
|
const disconnectEvent = event;
|
|
3498
3422
|
console.log(`[Daemon] Connection closed for ${projectId}: code=${disconnectEvent.code}, willReconnect=${disconnectEvent.willReconnect}`);
|
|
3499
3423
|
this.liveConnections.delete(projectPath);
|
|
3500
|
-
if (this.identityServer && this.liveConnections.size === 0) {
|
|
3501
|
-
this.identityServer.setConnected(false);
|
|
3502
|
-
}
|
|
3503
3424
|
if (!disconnectEvent.willReconnect) {
|
|
3504
3425
|
this.connections.delete(projectPath);
|
|
3505
3426
|
console.log(`[Daemon] Removed connection for ${projectPath} from map`);
|
|
@@ -3517,9 +3438,9 @@ var Daemon = class {
|
|
|
3517
3438
|
console.warn(`[Daemon] Could not read daemon PID:`, pidError instanceof Error ? pidError.message : pidError);
|
|
3518
3439
|
}
|
|
3519
3440
|
await client.connect(wsUrl, config.access_token, this.machineId, {
|
|
3520
|
-
hostname:
|
|
3521
|
-
osPlatform:
|
|
3522
|
-
osArch:
|
|
3441
|
+
hostname: os.hostname(),
|
|
3442
|
+
osPlatform: os.platform(),
|
|
3443
|
+
osArch: os.arch(),
|
|
3523
3444
|
daemonPid
|
|
3524
3445
|
});
|
|
3525
3446
|
console.log(`[Daemon] Successfully connected to project ${projectId}`);
|
|
@@ -3678,10 +3599,6 @@ var Daemon = class {
|
|
|
3678
3599
|
await connection.client.disconnect();
|
|
3679
3600
|
}
|
|
3680
3601
|
this.connections.clear();
|
|
3681
|
-
if (this.identityServer) {
|
|
3682
|
-
await this.identityServer.stop();
|
|
3683
|
-
this.identityServer = null;
|
|
3684
|
-
}
|
|
3685
3602
|
await this.ipcServer.stop();
|
|
3686
3603
|
console.log("[Daemon] Shutdown complete");
|
|
3687
3604
|
}
|