episoda 0.2.11 → 0.2.13

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.
@@ -1646,9 +1646,19 @@ var require_version = __commonJS({
1646
1646
  exports2.VERSION = void 0;
1647
1647
  var fs_1 = require("fs");
1648
1648
  var path_1 = require("path");
1649
- var packageJsonPath = (0, path_1.join)(__dirname, "..", "package.json");
1650
- var packageJson2 = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, "utf-8"));
1651
- exports2.VERSION = packageJson2.version;
1649
+ var FALLBACK_VERSION = "0.1.11";
1650
+ function getVersion() {
1651
+ try {
1652
+ const packageJsonPath = (0, path_1.join)(__dirname, "..", "package.json");
1653
+ if ((0, fs_1.existsSync)(packageJsonPath)) {
1654
+ const packageJson2 = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, "utf-8"));
1655
+ return packageJson2.version;
1656
+ }
1657
+ } catch {
1658
+ }
1659
+ return FALLBACK_VERSION;
1660
+ }
1661
+ exports2.VERSION = getVersion();
1652
1662
  }
1653
1663
  });
1654
1664
 
@@ -2068,11 +2078,11 @@ var require_auth = __commonJS({
2068
2078
  exports2.validateToken = validateToken;
2069
2079
  var fs6 = __importStar(require("fs"));
2070
2080
  var path7 = __importStar(require("path"));
2071
- var os4 = __importStar(require("os"));
2081
+ var os2 = __importStar(require("os"));
2072
2082
  var child_process_1 = require("child_process");
2073
2083
  var DEFAULT_CONFIG_FILE = "config.json";
2074
2084
  function getConfigDir5() {
2075
- return process.env.EPISODA_CONFIG_DIR || path7.join(os4.homedir(), ".episoda");
2085
+ return process.env.EPISODA_CONFIG_DIR || path7.join(os2.homedir(), ".episoda");
2076
2086
  }
2077
2087
  function getConfigPath(configPath) {
2078
2088
  if (configPath) {
@@ -2228,7 +2238,7 @@ var require_package = __commonJS({
2228
2238
  "package.json"(exports2, module2) {
2229
2239
  module2.exports = {
2230
2240
  name: "episoda",
2231
- version: "0.2.10",
2241
+ version: "0.2.12",
2232
2242
  description: "CLI tool for Episoda local development workflow orchestration",
2233
2243
  main: "dist/index.js",
2234
2244
  types: "dist/index.d.ts",
@@ -2283,19 +2293,29 @@ var require_package = __commonJS({
2283
2293
  });
2284
2294
 
2285
2295
  // src/daemon/machine-id.ts
2286
- var os = __toESM(require("os"));
2287
2296
  var fs = __toESM(require("fs"));
2288
2297
  var path = __toESM(require("path"));
2289
2298
  var crypto = __toESM(require("crypto"));
2290
2299
  var import_child_process = require("child_process");
2291
2300
  var import_core = __toESM(require_dist());
2301
+ function isValidUUID(str) {
2302
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2303
+ return uuidRegex.test(str);
2304
+ }
2292
2305
  async function getMachineId() {
2293
2306
  const machineIdPath = path.join((0, import_core.getConfigDir)(), "machine-id");
2294
2307
  try {
2295
2308
  if (fs.existsSync(machineIdPath)) {
2296
- const machineId2 = fs.readFileSync(machineIdPath, "utf-8").trim();
2297
- if (machineId2) {
2298
- return machineId2;
2309
+ const existingId = fs.readFileSync(machineIdPath, "utf-8").trim();
2310
+ if (existingId) {
2311
+ if (isValidUUID(existingId)) {
2312
+ return existingId;
2313
+ }
2314
+ console.log("[MachineId] Migrating legacy machine ID to UUID format...");
2315
+ const newUUID = generateMachineId();
2316
+ fs.writeFileSync(machineIdPath, newUUID, "utf-8");
2317
+ console.log(`[MachineId] Migrated: ${existingId} \u2192 ${newUUID}`);
2318
+ return newUUID;
2299
2319
  }
2300
2320
  }
2301
2321
  } catch (error) {
@@ -2354,10 +2374,21 @@ function getHardwareUUID() {
2354
2374
  return crypto.randomUUID();
2355
2375
  }
2356
2376
  function generateMachineId() {
2357
- const hostname4 = os.hostname();
2358
2377
  const hwUUID = getHardwareUUID();
2359
- const shortId = hwUUID.replace(/-/g, "").slice(0, 8).toLowerCase();
2360
- return `${hostname4}-${shortId}`;
2378
+ if (isValidUUID(hwUUID)) {
2379
+ return hwUUID.toLowerCase();
2380
+ }
2381
+ const hash = crypto.createHash("sha256").update(hwUUID).digest("hex");
2382
+ const uuid = [
2383
+ hash.slice(0, 8),
2384
+ hash.slice(8, 12),
2385
+ "4" + hash.slice(13, 16),
2386
+ // Version 4
2387
+ (parseInt(hash.slice(16, 17), 16) & 3 | 8).toString(16) + hash.slice(17, 20),
2388
+ // Variant
2389
+ hash.slice(20, 32)
2390
+ ].join("-");
2391
+ return uuid.toLowerCase();
2361
2392
  }
2362
2393
 
2363
2394
  // src/daemon/project-tracker.ts
@@ -2615,97 +2646,6 @@ function performBackgroundUpdate() {
2615
2646
  }
2616
2647
  }
2617
2648
 
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
2649
  // src/daemon/handlers/file-handlers.ts
2710
2650
  var fs4 = __toESM(require("fs"));
2711
2651
  var path5 = __toESM(require("path"));
@@ -3172,7 +3112,7 @@ async function handleExec(command, projectPath) {
3172
3112
 
3173
3113
  // src/daemon/daemon-process.ts
3174
3114
  var fs5 = __toESM(require("fs"));
3175
- var os3 = __toESM(require("os"));
3115
+ var os = __toESM(require("os"));
3176
3116
  var path6 = __toESM(require("path"));
3177
3117
  var packageJson = require_package();
3178
3118
  var Daemon = class {
@@ -3183,8 +3123,7 @@ var Daemon = class {
3183
3123
  this.deviceName = null;
3184
3124
  // EP661: Cached device name from server
3185
3125
  this.flyMachineId = null;
3186
- this.identityServer = null;
3187
- // EP803: Local identity server for browser detection
3126
+ // EP812: Removed identityServer - browser identity now uses cookie-based pairing
3188
3127
  this.connections = /* @__PURE__ */ new Map();
3189
3128
  // projectPath -> connection
3190
3129
  // EP701: Track which connections are currently live (WebSocket open)
@@ -3208,8 +3147,6 @@ var Daemon = class {
3208
3147
  }
3209
3148
  await this.ipcServer.start();
3210
3149
  console.log("[Daemon] IPC server started");
3211
- this.identityServer = new IdentityServer(this.machineId);
3212
- await this.identityServer.start();
3213
3150
  this.registerIPCHandlers();
3214
3151
  await this.restoreConnections();
3215
3152
  this.setupShutdownHandlers();
@@ -3252,9 +3189,9 @@ var Daemon = class {
3252
3189
  machineId: this.machineId,
3253
3190
  deviceId: this.deviceId,
3254
3191
  // EP726: UUID for unified device identification
3255
- hostname: os3.hostname(),
3256
- platform: os3.platform(),
3257
- arch: os3.arch(),
3192
+ hostname: os.hostname(),
3193
+ platform: os.platform(),
3194
+ arch: os.arch(),
3258
3195
  projects
3259
3196
  };
3260
3197
  });
@@ -3468,9 +3405,6 @@ var Daemon = class {
3468
3405
  console.log(`[Daemon] Authenticated for project ${projectId}`);
3469
3406
  touchProject(projectPath);
3470
3407
  this.liveConnections.add(projectPath);
3471
- if (this.identityServer) {
3472
- this.identityServer.setConnected(true);
3473
- }
3474
3408
  const authMessage = message;
3475
3409
  if (authMessage.userId && authMessage.workspaceId) {
3476
3410
  await this.configureGitUser(projectPath, authMessage.userId, authMessage.workspaceId, this.machineId, projectId, authMessage.deviceId);
@@ -3497,9 +3431,6 @@ var Daemon = class {
3497
3431
  const disconnectEvent = event;
3498
3432
  console.log(`[Daemon] Connection closed for ${projectId}: code=${disconnectEvent.code}, willReconnect=${disconnectEvent.willReconnect}`);
3499
3433
  this.liveConnections.delete(projectPath);
3500
- if (this.identityServer && this.liveConnections.size === 0) {
3501
- this.identityServer.setConnected(false);
3502
- }
3503
3434
  if (!disconnectEvent.willReconnect) {
3504
3435
  this.connections.delete(projectPath);
3505
3436
  console.log(`[Daemon] Removed connection for ${projectPath} from map`);
@@ -3517,9 +3448,9 @@ var Daemon = class {
3517
3448
  console.warn(`[Daemon] Could not read daemon PID:`, pidError instanceof Error ? pidError.message : pidError);
3518
3449
  }
3519
3450
  await client.connect(wsUrl, config.access_token, this.machineId, {
3520
- hostname: os3.hostname(),
3521
- osPlatform: os3.platform(),
3522
- osArch: os3.arch(),
3451
+ hostname: os.hostname(),
3452
+ osPlatform: os.platform(),
3453
+ osArch: os.arch(),
3523
3454
  daemonPid
3524
3455
  });
3525
3456
  console.log(`[Daemon] Successfully connected to project ${projectId}`);
@@ -3678,10 +3609,6 @@ var Daemon = class {
3678
3609
  await connection.client.disconnect();
3679
3610
  }
3680
3611
  this.connections.clear();
3681
- if (this.identityServer) {
3682
- await this.identityServer.stop();
3683
- this.identityServer = null;
3684
- }
3685
3612
  await this.ipcServer.stop();
3686
3613
  console.log("[Daemon] Shutdown complete");
3687
3614
  }