@mkterswingman/5mghost-yonder 0.0.25 → 0.0.26

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.
@@ -55,6 +55,9 @@ export interface SetupCookiesOptions {
55
55
  importOnly?: boolean;
56
56
  headed?: boolean;
57
57
  }
58
+ export declare class BrowserProfileLockedError extends Error {
59
+ constructor(message?: string);
60
+ }
58
61
  type SetupCookiesChromium = Awaited<ReturnType<SetupCookiesDeps["loadChromium"]>>;
59
62
  interface CdpCookie {
60
63
  name: string;
@@ -109,6 +109,12 @@ async function loadPlaywrightChromium() {
109
109
  const pw = await import("playwright");
110
110
  return pw.chromium;
111
111
  }
112
+ export class BrowserProfileLockedError extends Error {
113
+ constructor(message = "Chrome/Edge profile is locked by a running browser") {
114
+ super(message);
115
+ this.name = "BrowserProfileLockedError";
116
+ }
117
+ }
112
118
  function buildSetupCookiesDeps(overrides = {}) {
113
119
  return {
114
120
  ensureConfigDir,
@@ -194,6 +200,7 @@ async function terminateImportedBrowser(processHandle) {
194
200
  }
195
201
  export async function tryImportBrowserCookies(chromium, deps) {
196
202
  const candidates = deps.findImportableBrowserProfileCandidates();
203
+ let sawLockedProfile = false;
197
204
  if (candidates.length === 0) {
198
205
  return false;
199
206
  }
@@ -201,7 +208,19 @@ export async function tryImportBrowserCookies(chromium, deps) {
201
208
  const candidate = candidates[index];
202
209
  const isLastCandidate = index === candidates.length - 1;
203
210
  deps.log(`Trying to import existing YouTube login from ${candidate.label} (${candidate.profileLabel})...`);
204
- const importedCookies = await deps.readImportedBrowserCookies(candidate, chromium, deps);
211
+ let importedCookies = null;
212
+ try {
213
+ importedCookies = await deps.readImportedBrowserCookies(candidate, chromium, deps);
214
+ }
215
+ catch (err) {
216
+ if (err instanceof BrowserProfileLockedError) {
217
+ sawLockedProfile = true;
218
+ deps.log(`${candidate.label} (${candidate.profileLabel}) profile is locked by a running browser.`);
219
+ }
220
+ else {
221
+ throw err;
222
+ }
223
+ }
205
224
  if (importedCookies) {
206
225
  await deps.saveCookiesAndClose({ close: async () => { } }, importedCookies, true);
207
226
  deps.log(`✅ Imported YouTube session from ${candidate.label} (${candidate.profileLabel})\n`);
@@ -212,6 +231,9 @@ export async function tryImportBrowserCookies(chromium, deps) {
212
231
  deps.log(`${candidate.label} (${candidate.profileLabel}) import unavailable, trying ${nextCandidate.label} (${nextCandidate.profileLabel})...`);
213
232
  }
214
233
  }
234
+ if (sawLockedProfile) {
235
+ throw new BrowserProfileLockedError("Chrome/Edge profile is locked by a running browser. Close Chrome/Edge and rerun `yt-mcp setup-cookies`, or continue with headed browser login.");
236
+ }
215
237
  deps.log("Browser profile import failed, falling back to manual login...\n");
216
238
  return false;
217
239
  }
@@ -255,7 +277,14 @@ export async function readImportedBrowserCookies(candidate, chromium, deps) {
255
277
  }
256
278
  return cookies;
257
279
  }
258
- catch {
280
+ catch (err) {
281
+ const message = err instanceof Error ? err.message : String(err);
282
+ const code = typeof err === "object" && err && "code" in err ? String(err.code ?? "") : "";
283
+ if (code === "EBUSY" ||
284
+ code === "EPERM" ||
285
+ /resource busy|being used by another process|used by another process|device or resource busy|operation not permitted/i.test(message)) {
286
+ throw new BrowserProfileLockedError();
287
+ }
259
288
  return null;
260
289
  }
261
290
  finally {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mkterswingman/5mghost-yonder",
3
- "version": "0.0.25",
3
+ "version": "0.0.26",
4
4
  "description": "Internal MCP client with local data tools and remote API proxy",
5
5
  "type": "module",
6
6
  "bin": {