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.
package/dist/index.js CHANGED
@@ -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 packageJson = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, "utf-8"));
1651
- exports2.VERSION = packageJson.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 packageJson = JSON.parse((0, fs_1.readFileSync)(packageJsonPath, "utf-8"));
1655
+ return packageJson.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 fs5 = __importStar(require("fs"));
2070
2080
  var path7 = __importStar(require("path"));
2071
- var os3 = __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 getConfigDir4() {
2075
- return process.env.EPISODA_CONFIG_DIR || path7.join(os3.homedir(), ".episoda");
2085
+ return process.env.EPISODA_CONFIG_DIR || path7.join(os2.homedir(), ".episoda");
2076
2086
  }
2077
2087
  function getConfigPath3(configPath) {
2078
2088
  if (configPath) {
@@ -2923,26 +2933,36 @@ Received ${signal}, shutting down...`);
2923
2933
  }
2924
2934
 
2925
2935
  // src/commands/auth.ts
2926
- var os2 = __toESM(require("os"));
2936
+ var os = __toESM(require("os"));
2927
2937
  var fs4 = __toESM(require("fs"));
2928
2938
  var path6 = __toESM(require("path"));
2929
2939
  var import_child_process4 = require("child_process");
2930
2940
  var import_core5 = __toESM(require_dist());
2931
2941
 
2932
2942
  // src/daemon/machine-id.ts
2933
- var os = __toESM(require("os"));
2934
2943
  var fs3 = __toESM(require("fs"));
2935
2944
  var path5 = __toESM(require("path"));
2936
2945
  var crypto2 = __toESM(require("crypto"));
2937
2946
  var import_child_process3 = require("child_process");
2938
2947
  var import_core4 = __toESM(require_dist());
2948
+ function isValidUUID(str) {
2949
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2950
+ return uuidRegex.test(str);
2951
+ }
2939
2952
  async function getMachineId() {
2940
2953
  const machineIdPath = path5.join((0, import_core4.getConfigDir)(), "machine-id");
2941
2954
  try {
2942
2955
  if (fs3.existsSync(machineIdPath)) {
2943
- const machineId2 = fs3.readFileSync(machineIdPath, "utf-8").trim();
2944
- if (machineId2) {
2945
- return machineId2;
2956
+ const existingId = fs3.readFileSync(machineIdPath, "utf-8").trim();
2957
+ if (existingId) {
2958
+ if (isValidUUID(existingId)) {
2959
+ return existingId;
2960
+ }
2961
+ console.log("[MachineId] Migrating legacy machine ID to UUID format...");
2962
+ const newUUID = generateMachineId();
2963
+ fs3.writeFileSync(machineIdPath, newUUID, "utf-8");
2964
+ console.log(`[MachineId] Migrated: ${existingId} \u2192 ${newUUID}`);
2965
+ return newUUID;
2946
2966
  }
2947
2967
  }
2948
2968
  } catch (error) {
@@ -3001,10 +3021,21 @@ function getHardwareUUID() {
3001
3021
  return crypto2.randomUUID();
3002
3022
  }
3003
3023
  function generateMachineId() {
3004
- const hostname2 = os.hostname();
3005
3024
  const hwUUID = getHardwareUUID();
3006
- const shortId = hwUUID.replace(/-/g, "").slice(0, 8).toLowerCase();
3007
- return `${hostname2}-${shortId}`;
3025
+ if (isValidUUID(hwUUID)) {
3026
+ return hwUUID.toLowerCase();
3027
+ }
3028
+ const hash = crypto2.createHash("sha256").update(hwUUID).digest("hex");
3029
+ const uuid = [
3030
+ hash.slice(0, 8),
3031
+ hash.slice(8, 12),
3032
+ "4" + hash.slice(13, 16),
3033
+ // Version 4
3034
+ (parseInt(hash.slice(16, 17), 16) & 3 | 8).toString(16) + hash.slice(17, 20),
3035
+ // Variant
3036
+ hash.slice(20, 32)
3037
+ ].join("-");
3038
+ return uuid.toLowerCase();
3008
3039
  }
3009
3040
 
3010
3041
  // src/git-helpers/git-credential-helper.ts
@@ -3330,8 +3361,9 @@ async function authCommand(options = {}) {
3330
3361
  const apiUrl = options.apiUrl || process.env.EPISODA_API_URL || "https://episoda.dev";
3331
3362
  status.info("Initializing Episoda CLI...");
3332
3363
  status.info("");
3364
+ const machineId = await getMachineId();
3333
3365
  status.info("Step 1/3: Requesting authorization code...");
3334
- const deviceAuth = await initiateDeviceFlow(apiUrl);
3366
+ const deviceAuth = await initiateDeviceFlow(apiUrl, machineId);
3335
3367
  status.success(`\u2713 Authorization code received: ${deviceAuth.user_code}`);
3336
3368
  status.info("");
3337
3369
  status.info("Step 2/3: Opening browser for authorization...");
@@ -3347,7 +3379,6 @@ async function authCommand(options = {}) {
3347
3379
  status.success("\u2713 Authorization successful!");
3348
3380
  status.info("");
3349
3381
  status.info("Step 3/3: Exchanging authorization for access token...");
3350
- const machineId = await getMachineId();
3351
3382
  const tokenResponse = await exchangeDeviceCode(apiUrl, deviceAuth.device_code, machineId);
3352
3383
  status.success("\u2713 Access token received");
3353
3384
  status.info(` Project: ${tokenResponse.project_uid}`);
@@ -3381,13 +3412,16 @@ async function authCommand(options = {}) {
3381
3412
  status.info(" \u2022 Git operations will use Episoda auth automatically");
3382
3413
  status.info("");
3383
3414
  }
3384
- async function initiateDeviceFlow(apiUrl) {
3415
+ async function initiateDeviceFlow(apiUrl, machineId) {
3385
3416
  const response = await fetch(`${apiUrl}/api/oauth/code`, {
3386
3417
  method: "POST",
3387
3418
  headers: {
3388
3419
  "Content-Type": "application/json"
3389
3420
  },
3390
- body: JSON.stringify({})
3421
+ body: JSON.stringify({
3422
+ machine_id: machineId
3423
+ // EP812: For cookie-based device pairing
3424
+ })
3391
3425
  });
3392
3426
  if (!response.ok) {
3393
3427
  const error = await response.json();
@@ -3488,7 +3522,7 @@ async function exchangeDeviceCode(apiUrl, deviceCode, machineId) {
3488
3522
  return tokenResponse;
3489
3523
  }
3490
3524
  function openBrowser(url) {
3491
- const platform2 = os2.platform();
3525
+ const platform2 = os.platform();
3492
3526
  let command;
3493
3527
  let args;
3494
3528
  switch (platform2) {
@@ -3516,7 +3550,7 @@ function openBrowser(url) {
3516
3550
  }
3517
3551
  async function installGitCredentialHelper(apiUrl) {
3518
3552
  try {
3519
- const homeDir = os2.homedir();
3553
+ const homeDir = os.homedir();
3520
3554
  const episodaBinDir = path6.join(homeDir, ".episoda", "bin");
3521
3555
  const helperPath = path6.join(episodaBinDir, "git-credential-episoda");
3522
3556
  fs4.mkdirSync(episodaBinDir, { recursive: true });
@@ -3548,11 +3582,11 @@ async function installGitCredentialHelper(apiUrl) {
3548
3582
  }
3549
3583
  }
3550
3584
  function updateShellProfile(binDir) {
3551
- const platform2 = os2.platform();
3585
+ const platform2 = os.platform();
3552
3586
  if (platform2 === "win32") {
3553
3587
  return;
3554
3588
  }
3555
- const homeDir = os2.homedir();
3589
+ const homeDir = os.homedir();
3556
3590
  const profiles = [
3557
3591
  path6.join(homeDir, ".bashrc"),
3558
3592
  path6.join(homeDir, ".zshrc"),