episoda 0.2.10 → 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/index.js CHANGED
@@ -2068,11 +2068,11 @@ var require_auth = __commonJS({
2068
2068
  exports2.validateToken = validateToken;
2069
2069
  var fs5 = __importStar(require("fs"));
2070
2070
  var path7 = __importStar(require("path"));
2071
- var os3 = __importStar(require("os"));
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 getConfigDir4() {
2075
- return process.env.EPISODA_CONFIG_DIR || path7.join(os3.homedir(), ".episoda");
2075
+ return process.env.EPISODA_CONFIG_DIR || path7.join(os2.homedir(), ".episoda");
2076
2076
  }
2077
2077
  function getConfigPath3(configPath) {
2078
2078
  if (configPath) {
@@ -2541,7 +2541,7 @@ async function startDaemon() {
2541
2541
  if (!fs2.existsSync(configDir)) {
2542
2542
  fs2.mkdirSync(configDir, { recursive: true });
2543
2543
  }
2544
- const daemonScript = path2.join(__dirname, "daemon-process.js");
2544
+ const daemonScript = path2.join(__dirname, "daemon", "daemon-process.js");
2545
2545
  if (!fs2.existsSync(daemonScript)) {
2546
2546
  throw new Error(`Daemon script not found: ${daemonScript}. Make sure CLI is built.`);
2547
2547
  }
@@ -2923,26 +2923,36 @@ Received ${signal}, shutting down...`);
2923
2923
  }
2924
2924
 
2925
2925
  // src/commands/auth.ts
2926
- var os2 = __toESM(require("os"));
2926
+ var os = __toESM(require("os"));
2927
2927
  var fs4 = __toESM(require("fs"));
2928
2928
  var path6 = __toESM(require("path"));
2929
2929
  var import_child_process4 = require("child_process");
2930
2930
  var import_core5 = __toESM(require_dist());
2931
2931
 
2932
2932
  // src/daemon/machine-id.ts
2933
- var os = __toESM(require("os"));
2934
2933
  var fs3 = __toESM(require("fs"));
2935
2934
  var path5 = __toESM(require("path"));
2936
2935
  var crypto2 = __toESM(require("crypto"));
2937
2936
  var import_child_process3 = require("child_process");
2938
2937
  var import_core4 = __toESM(require_dist());
2938
+ function isValidUUID(str) {
2939
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2940
+ return uuidRegex.test(str);
2941
+ }
2939
2942
  async function getMachineId() {
2940
2943
  const machineIdPath = path5.join((0, import_core4.getConfigDir)(), "machine-id");
2941
2944
  try {
2942
2945
  if (fs3.existsSync(machineIdPath)) {
2943
- const machineId2 = fs3.readFileSync(machineIdPath, "utf-8").trim();
2944
- if (machineId2) {
2945
- return machineId2;
2946
+ const existingId = fs3.readFileSync(machineIdPath, "utf-8").trim();
2947
+ if (existingId) {
2948
+ if (isValidUUID(existingId)) {
2949
+ return existingId;
2950
+ }
2951
+ console.log("[MachineId] Migrating legacy machine ID to UUID format...");
2952
+ const newUUID = generateMachineId();
2953
+ fs3.writeFileSync(machineIdPath, newUUID, "utf-8");
2954
+ console.log(`[MachineId] Migrated: ${existingId} \u2192 ${newUUID}`);
2955
+ return newUUID;
2946
2956
  }
2947
2957
  }
2948
2958
  } catch (error) {
@@ -3001,10 +3011,21 @@ function getHardwareUUID() {
3001
3011
  return crypto2.randomUUID();
3002
3012
  }
3003
3013
  function generateMachineId() {
3004
- const hostname2 = os.hostname();
3005
3014
  const hwUUID = getHardwareUUID();
3006
- const shortId = hwUUID.replace(/-/g, "").slice(0, 8).toLowerCase();
3007
- return `${hostname2}-${shortId}`;
3015
+ if (isValidUUID(hwUUID)) {
3016
+ return hwUUID.toLowerCase();
3017
+ }
3018
+ const hash = crypto2.createHash("sha256").update(hwUUID).digest("hex");
3019
+ const uuid = [
3020
+ hash.slice(0, 8),
3021
+ hash.slice(8, 12),
3022
+ "4" + hash.slice(13, 16),
3023
+ // Version 4
3024
+ (parseInt(hash.slice(16, 17), 16) & 3 | 8).toString(16) + hash.slice(17, 20),
3025
+ // Variant
3026
+ hash.slice(20, 32)
3027
+ ].join("-");
3028
+ return uuid.toLowerCase();
3008
3029
  }
3009
3030
 
3010
3031
  // src/git-helpers/git-credential-helper.ts
@@ -3330,8 +3351,9 @@ async function authCommand(options = {}) {
3330
3351
  const apiUrl = options.apiUrl || process.env.EPISODA_API_URL || "https://episoda.dev";
3331
3352
  status.info("Initializing Episoda CLI...");
3332
3353
  status.info("");
3354
+ const machineId = await getMachineId();
3333
3355
  status.info("Step 1/3: Requesting authorization code...");
3334
- const deviceAuth = await initiateDeviceFlow(apiUrl);
3356
+ const deviceAuth = await initiateDeviceFlow(apiUrl, machineId);
3335
3357
  status.success(`\u2713 Authorization code received: ${deviceAuth.user_code}`);
3336
3358
  status.info("");
3337
3359
  status.info("Step 2/3: Opening browser for authorization...");
@@ -3347,7 +3369,6 @@ async function authCommand(options = {}) {
3347
3369
  status.success("\u2713 Authorization successful!");
3348
3370
  status.info("");
3349
3371
  status.info("Step 3/3: Exchanging authorization for access token...");
3350
- const machineId = await getMachineId();
3351
3372
  const tokenResponse = await exchangeDeviceCode(apiUrl, deviceAuth.device_code, machineId);
3352
3373
  status.success("\u2713 Access token received");
3353
3374
  status.info(` Project: ${tokenResponse.project_uid}`);
@@ -3381,13 +3402,16 @@ async function authCommand(options = {}) {
3381
3402
  status.info(" \u2022 Git operations will use Episoda auth automatically");
3382
3403
  status.info("");
3383
3404
  }
3384
- async function initiateDeviceFlow(apiUrl) {
3405
+ async function initiateDeviceFlow(apiUrl, machineId) {
3385
3406
  const response = await fetch(`${apiUrl}/api/oauth/code`, {
3386
3407
  method: "POST",
3387
3408
  headers: {
3388
3409
  "Content-Type": "application/json"
3389
3410
  },
3390
- body: JSON.stringify({})
3411
+ body: JSON.stringify({
3412
+ machine_id: machineId
3413
+ // EP812: For cookie-based device pairing
3414
+ })
3391
3415
  });
3392
3416
  if (!response.ok) {
3393
3417
  const error = await response.json();
@@ -3488,7 +3512,7 @@ async function exchangeDeviceCode(apiUrl, deviceCode, machineId) {
3488
3512
  return tokenResponse;
3489
3513
  }
3490
3514
  function openBrowser(url) {
3491
- const platform2 = os2.platform();
3515
+ const platform2 = os.platform();
3492
3516
  let command;
3493
3517
  let args;
3494
3518
  switch (platform2) {
@@ -3516,7 +3540,7 @@ function openBrowser(url) {
3516
3540
  }
3517
3541
  async function installGitCredentialHelper(apiUrl) {
3518
3542
  try {
3519
- const homeDir = os2.homedir();
3543
+ const homeDir = os.homedir();
3520
3544
  const episodaBinDir = path6.join(homeDir, ".episoda", "bin");
3521
3545
  const helperPath = path6.join(episodaBinDir, "git-credential-episoda");
3522
3546
  fs4.mkdirSync(episodaBinDir, { recursive: true });
@@ -3548,11 +3572,11 @@ async function installGitCredentialHelper(apiUrl) {
3548
3572
  }
3549
3573
  }
3550
3574
  function updateShellProfile(binDir) {
3551
- const platform2 = os2.platform();
3575
+ const platform2 = os.platform();
3552
3576
  if (platform2 === "win32") {
3553
3577
  return;
3554
3578
  }
3555
- const homeDir = os2.homedir();
3579
+ const homeDir = os.homedir();
3556
3580
  const profiles = [
3557
3581
  path6.join(homeDir, ".bashrc"),
3558
3582
  path6.join(homeDir, ".zshrc"),